mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-06 07:26:43 -04:00
Configure compression for keynote benchmark (#4743)
# Description of Changes Message compression is now configurable for both the rust and typescript keynote benchmark clients with the default being no compression. Before this patch the rust client was using no compression and the typescript client was using gzip by default. # API and ABI breaking changes None # Expected complexity level and risk 1 # Testing Manual
This commit is contained in:
@@ -26,6 +26,7 @@ SQLITE_MODE=default
|
||||
STDB_URL=ws://127.0.0.1:3000
|
||||
STDB_MODULE=test-1
|
||||
STDB_MODULE_PATH=./spacetimedb
|
||||
STDB_COMPRESSION=none
|
||||
STDB_CONFIRMED_READS=1
|
||||
|
||||
# ===== Supabase =====
|
||||
|
||||
@@ -31,6 +31,7 @@ The script will:
|
||||
- `--concurrency N` - Concurrent connections (default: 50)
|
||||
- `--alpha N` - Contention level (default: 1.5)
|
||||
- `--systems a,b,c` - Systems to compare (default: convex,spacetimedb)
|
||||
- `--stdb-compression none|gzip` - SpacetimeDB client compression mode (default: none)
|
||||
- `--skip-prep` - Skip database seeding
|
||||
- `--no-animation` - Disable animated output
|
||||
|
||||
@@ -90,6 +91,7 @@ Copy `.env.example` to `.env` and adjust.
|
||||
- `STDB_URL` – WebSocket URL for SpacetimeDB
|
||||
- `STDB_MODULE` – module name to load (e.g. `test-1`)
|
||||
- `STDB_MODULE_PATH` – filesystem path to the module source (for local dev)
|
||||
- `STDB_COMPRESSION` – SpacetimeDB benchmark client compression (`none` or `gzip`)
|
||||
- `STDB_CONFIRMED_READS` – `1` = force confirmed reads on, `0` = force them off
|
||||
|
||||
**Supabase:**
|
||||
@@ -166,7 +168,7 @@ cd ..
|
||||
### 1. Run a test
|
||||
|
||||
```bash
|
||||
npm run bench -- [test-name] [--seconds N] [--concurrency N] [--alpha A] [--connectors list]
|
||||
npm run bench -- [test-name] [--seconds N] [--concurrency N] [--alpha A] [--connectors list] [--stdb-compression none|gzip]
|
||||
```
|
||||
|
||||
Examples:
|
||||
@@ -184,6 +186,9 @@ npm run bench -- test-1 --seconds 10 --concurrency 100
|
||||
# Heavier skew on hot accounts
|
||||
npm run bench -- test-1 --alpha 2.0
|
||||
|
||||
# Enable gzip for the SpacetimeDB benchmark client
|
||||
npm run bench -- test-1 --connectors spacetimedb --stdb-compression gzip
|
||||
|
||||
# Only run selected connectors
|
||||
npm run bench -- test-1 --connectors spacetimedb,sqlite_rpc
|
||||
```
|
||||
@@ -256,6 +261,7 @@ pnpm run bench-dist-coordinator -- \
|
||||
--verify 1 \
|
||||
--stdb-url ws://127.0.0.1:3000 \
|
||||
--stdb-module test-1 \
|
||||
--stdb-compression none \
|
||||
--bind 127.0.0.1 \
|
||||
--port 8080
|
||||
```
|
||||
@@ -287,7 +293,8 @@ pnpm run bench-dist-generator -- \
|
||||
--open-parallelism 128 \
|
||||
--control-retries 3 \
|
||||
--stdb-url ws://127.0.0.1:3000 \
|
||||
--stdb-module test-1
|
||||
--stdb-module test-1 \
|
||||
--stdb-compression none
|
||||
```
|
||||
|
||||
On **generator machine 2**:
|
||||
@@ -306,7 +313,8 @@ pnpm run bench-dist-generator -- \
|
||||
--open-parallelism 128 \
|
||||
--control-retries 3 \
|
||||
--stdb-url ws://127.0.0.1:3000 \
|
||||
--stdb-module test-1
|
||||
--stdb-module test-1 \
|
||||
--stdb-compression none
|
||||
```
|
||||
|
||||
Repeat that on as many generator machines as needed, adjusting `--id` and `--concurrency` for each process.
|
||||
|
||||
@@ -91,6 +91,7 @@ docker compose run --rm bench --seconds 10 --concurrency 50 --alpha XX --connect
|
||||
- `--concurrency 50`: Number of concurrent client connections
|
||||
- `--alpha 0`: ~0% contention (uniform account distribution)
|
||||
- `--alpha 1.5`: ~80% contention (Zipf distribution concentrating on hot accounts)
|
||||
- `--stdb-compression none|gzip`: SpacetimeDB client compression mode (default: `none`)
|
||||
|
||||
### Hardware Configuration
|
||||
|
||||
|
||||
@@ -30,6 +30,21 @@ const CONFIRMED_READS: bool = true;
|
||||
// Max inflight reducer calls imposed by the server.
|
||||
const MAX_INFLIGHT_REDUCERS: u64 = 16384;
|
||||
|
||||
#[derive(Clone, Copy, Debug, clap::ValueEnum)]
|
||||
enum CliCompression {
|
||||
None,
|
||||
Gzip,
|
||||
}
|
||||
|
||||
impl From<CliCompression> for Compression {
|
||||
fn from(value: CliCompression) -> Self {
|
||||
match value {
|
||||
CliCompression::None => Compression::None,
|
||||
CliCompression::Gzip => Compression::Gzip,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When called from within an async context, return a handle to it (and no
|
||||
// `Runtime`), otherwise create a fresh `Runtime` and return it along with a
|
||||
// handle to it.
|
||||
@@ -55,7 +70,7 @@ async fn init_conn(cli: &Common, handle: &Handle) -> (JoinHandle<()>, Recv, Send
|
||||
let server: &str = &cli.server;
|
||||
let uri = server.try_into().unwrap();
|
||||
let params = WsParams {
|
||||
compression: Compression::None,
|
||||
compression: cli.compression.into(),
|
||||
light: true,
|
||||
confirmed: cli.confirmed_reads.unwrap_or(CONFIRMED_READS).into(),
|
||||
};
|
||||
@@ -261,6 +276,9 @@ struct Common {
|
||||
#[arg(short, long, default_value = MODULE)]
|
||||
module: String,
|
||||
|
||||
#[arg(long, value_enum, default_value_t = CliCompression::None)]
|
||||
compression: CliCompression,
|
||||
|
||||
#[arg(long)]
|
||||
confirmed_reads: Option<bool>,
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ export const validConnectors = [
|
||||
|
||||
export type ConnectorKey = (typeof validConnectors)[number];
|
||||
|
||||
export const validStdbCompressions = ['none', 'gzip'] as const;
|
||||
|
||||
export type StdbCompression = (typeof validStdbCompressions)[number];
|
||||
|
||||
export const defaultDemoSystems: readonly ConnectorKey[] = [
|
||||
'convex',
|
||||
'spacetimedb',
|
||||
@@ -39,6 +43,7 @@ export interface SharedRuntimeConfig {
|
||||
stdbUrl: string;
|
||||
stdbModule: string;
|
||||
stdbModulePath: string;
|
||||
stdbCompression: StdbCompression;
|
||||
stdbConfirmedReads: boolean;
|
||||
useDocker: boolean;
|
||||
useSpacetimeMetricsEndpoint: boolean;
|
||||
@@ -82,6 +87,7 @@ export type ConnectorRuntimeConfig = Pick<
|
||||
| 'bunUrl'
|
||||
| 'convexUrl'
|
||||
| 'initialBalance'
|
||||
| 'stdbCompression'
|
||||
| 'stdbConfirmedReads'
|
||||
| 'stdbModule'
|
||||
| 'stdbUrl'
|
||||
@@ -89,6 +95,7 @@ export type ConnectorRuntimeConfig = Pick<
|
||||
|
||||
export interface SpacetimeConnectorConfig {
|
||||
initialBalance: number;
|
||||
stdbCompression: StdbCompression;
|
||||
stdbConfirmedReads: boolean;
|
||||
stdbModule: string;
|
||||
stdbUrl: string;
|
||||
@@ -131,6 +138,19 @@ export function normalizeStdbUrl(url: string): string {
|
||||
return url.replace(/^(http|ws)s?:\/\//, '');
|
||||
}
|
||||
|
||||
export function parseStdbCompression(
|
||||
raw: string,
|
||||
label: string,
|
||||
): StdbCompression {
|
||||
if (validStdbCompressions.includes(raw as StdbCompression)) {
|
||||
return raw as StdbCompression;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`invalid value for ${label}: ${raw} (expected one of: ${validStdbCompressions.join(', ')})`,
|
||||
);
|
||||
}
|
||||
|
||||
export function readNumberEnv(
|
||||
name: string,
|
||||
defaultValue: number,
|
||||
@@ -210,6 +230,10 @@ export function getSharedRuntimeDefaults(
|
||||
stdbUrl: normalizeStdbUrl(readStringEnv('STDB_URL', '127.0.0.1:3000', env)),
|
||||
stdbModule: readStringEnv('STDB_MODULE', 'test-1', env),
|
||||
stdbModulePath: readStringEnv('STDB_MODULE_PATH', './spacetimedb', env),
|
||||
stdbCompression: parseStdbCompression(
|
||||
readStringEnv('STDB_COMPRESSION', 'none', env),
|
||||
'STDB_COMPRESSION',
|
||||
),
|
||||
stdbConfirmedReads: readBooleanEnv('STDB_CONFIRMED_READS', true, env),
|
||||
useDocker: readBooleanEnv('USE_DOCKER', false, env),
|
||||
useSpacetimeMetricsEndpoint: readBooleanEnv(
|
||||
|
||||
@@ -23,6 +23,7 @@ const toSpacetimeConfig = (
|
||||
config: ConnectorRuntimeConfig,
|
||||
): SpacetimeConnectorConfig => ({
|
||||
initialBalance: config.initialBalance,
|
||||
stdbCompression: config.stdbCompression,
|
||||
stdbConfirmedReads: config.stdbConfirmedReads,
|
||||
stdbModule: config.stdbModule,
|
||||
stdbUrl: config.stdbUrl,
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { SpacetimeConnectorConfig } from '../config.ts';
|
||||
export function spacetimedb(config: SpacetimeConnectorConfig): ReducerConnector {
|
||||
const {
|
||||
initialBalance,
|
||||
stdbCompression,
|
||||
stdbConfirmedReads,
|
||||
stdbModule: moduleName,
|
||||
stdbUrl: url,
|
||||
@@ -33,6 +34,7 @@ export function spacetimedb(config: SpacetimeConnectorConfig): ReducerConnector
|
||||
const builder = Db.builder()
|
||||
.withUri(deriveWebsocketUrl(url))
|
||||
.withDatabaseName(moduleName)
|
||||
.withCompression(stdbCompression)
|
||||
.withConfirmedReads(stdbConfirmedReads)
|
||||
.onConnect((ctx) => {
|
||||
console.log('[stdb] connected');
|
||||
|
||||
@@ -23,6 +23,7 @@ const {
|
||||
noAnimation,
|
||||
seconds,
|
||||
skipPrep,
|
||||
stdbCompression,
|
||||
stdbConfirmedReads,
|
||||
stdbModule,
|
||||
stdbModulePath,
|
||||
@@ -277,6 +278,8 @@ async function runBenchmarkStdb(): Promise<BenchResult | null> {
|
||||
'ws://' + stdbUrl,
|
||||
'--module',
|
||||
stdbModule,
|
||||
'--compression',
|
||||
stdbCompression,
|
||||
'--duration',
|
||||
`${seconds}s`,
|
||||
'--connections',
|
||||
|
||||
@@ -6,7 +6,9 @@ import { join } from 'node:path';
|
||||
import { spacetimedb } from '../connectors/spacetimedb.ts';
|
||||
import {
|
||||
getSharedRuntimeDefaults,
|
||||
parseStdbCompression,
|
||||
type SpacetimeConnectorConfig,
|
||||
type StdbCompression,
|
||||
} from '../config.ts';
|
||||
import { getSpacetimeCommittedTransfers } from '../core/spacetimeMetrics.ts';
|
||||
import { normalizeStdbUrl } from '../core/stdbUrl.ts';
|
||||
@@ -74,13 +76,18 @@ async function readJsonBody<T>(req: IncomingMessage): Promise<T> {
|
||||
return JSON.parse(raw) as T;
|
||||
}
|
||||
|
||||
async function runVerification(url: string, moduleName: string): Promise<void> {
|
||||
async function runVerification(
|
||||
url: string,
|
||||
moduleName: string,
|
||||
compression: StdbCompression,
|
||||
): Promise<void> {
|
||||
const prevVerify = process.env.VERIFY;
|
||||
process.env.VERIFY = '1';
|
||||
|
||||
const defaults = getSharedRuntimeDefaults();
|
||||
const config: SpacetimeConnectorConfig = {
|
||||
initialBalance: defaults.initialBalance,
|
||||
stdbCompression: compression,
|
||||
stdbConfirmedReads: defaults.stdbConfirmedReads,
|
||||
stdbModule: moduleName,
|
||||
stdbUrl: url,
|
||||
@@ -110,6 +117,7 @@ class DistributedCoordinator {
|
||||
private readonly resultsDir: string;
|
||||
private readonly stdbUrl: string;
|
||||
private readonly moduleName: string;
|
||||
private readonly stdbCompression: StdbCompression;
|
||||
|
||||
private readonly generators = new Map<string, GeneratorRecord>();
|
||||
private phase: CoordinatorPhase = 'idle';
|
||||
@@ -128,6 +136,7 @@ class DistributedCoordinator {
|
||||
resultsDir: string;
|
||||
stdbUrl: string;
|
||||
moduleName: string;
|
||||
stdbCompression: StdbCompression;
|
||||
}) {
|
||||
this.testName = opts.testName;
|
||||
this.connectorName = opts.connectorName;
|
||||
@@ -138,6 +147,7 @@ class DistributedCoordinator {
|
||||
this.resultsDir = opts.resultsDir;
|
||||
this.stdbUrl = opts.stdbUrl;
|
||||
this.moduleName = opts.moduleName;
|
||||
this.stdbCompression = opts.stdbCompression;
|
||||
}
|
||||
|
||||
snapshot(): CoordinatorState {
|
||||
@@ -326,7 +336,11 @@ class DistributedCoordinator {
|
||||
|
||||
if (this.verifyAfterEpoch) {
|
||||
try {
|
||||
await runVerification(this.stdbUrl, this.moduleName);
|
||||
await runVerification(
|
||||
this.stdbUrl,
|
||||
this.moduleName,
|
||||
this.stdbCompression,
|
||||
);
|
||||
verification = 'passed';
|
||||
} catch (err) {
|
||||
verification = 'failed';
|
||||
@@ -450,11 +464,16 @@ async function main(): Promise<void> {
|
||||
process.env.STDB_URL ?? 'ws://127.0.0.1:3000',
|
||||
);
|
||||
const stdbUrl = normalizeStdbUrl(rawStdbUrl);
|
||||
const defaults = getSharedRuntimeDefaults();
|
||||
const moduleName = getStringFlag(
|
||||
flags,
|
||||
'stdb-module',
|
||||
process.env.STDB_MODULE ?? 'test-1',
|
||||
);
|
||||
const stdbCompression = parseStdbCompression(
|
||||
getStringFlag(flags, 'stdb-compression', defaults.stdbCompression),
|
||||
'--stdb-compression',
|
||||
);
|
||||
const initialIds = getStringListFlag(flags, 'generator-ids');
|
||||
|
||||
const coordinator = new DistributedCoordinator({
|
||||
@@ -467,6 +486,7 @@ async function main(): Promise<void> {
|
||||
resultsDir,
|
||||
stdbUrl,
|
||||
moduleName,
|
||||
stdbCompression,
|
||||
});
|
||||
|
||||
const server = createServer(async (req, res) => {
|
||||
@@ -530,7 +550,7 @@ async function main(): Promise<void> {
|
||||
});
|
||||
|
||||
console.log(
|
||||
`[coordinator] listening on http://${bind}:${port} test=${testName} connector=${connectorName} warmup=${warmupSeconds}s window=${windowSeconds}s verify=${verifyAfterEpoch ? 'on' : 'off'} stdb=${stdbUrl}`,
|
||||
`[coordinator] listening on http://${bind}:${port} test=${testName} connector=${connectorName} warmup=${warmupSeconds}s window=${windowSeconds}s verify=${verifyAfterEpoch ? 'on' : 'off'} stdb=${stdbUrl} compression=${stdbCompression}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { hostname as getHostname } from 'node:os';
|
||||
import { spacetimedb } from '../connectors/spacetimedb.ts';
|
||||
import {
|
||||
getSharedRuntimeDefaults,
|
||||
parseStdbCompression,
|
||||
type SpacetimeConnectorConfig,
|
||||
} from '../config.ts';
|
||||
import type { ReducerConnector } from '../core/connectors.ts';
|
||||
@@ -58,8 +59,13 @@ async function main(): Promise<void> {
|
||||
process.env.STDB_MODULE ?? 'test-1',
|
||||
);
|
||||
const defaults = getSharedRuntimeDefaults();
|
||||
const stdbCompression = parseStdbCompression(
|
||||
getStringFlag(flags, 'stdb-compression', defaults.stdbCompression),
|
||||
'--stdb-compression',
|
||||
);
|
||||
const connectorConfig: SpacetimeConnectorConfig = {
|
||||
initialBalance: defaults.initialBalance,
|
||||
stdbCompression,
|
||||
stdbConfirmedReads: defaults.stdbConfirmedReads,
|
||||
stdbModule: moduleName,
|
||||
stdbUrl,
|
||||
@@ -123,7 +129,7 @@ async function main(): Promise<void> {
|
||||
}, pollMs, controlRetries, () => !stopping);
|
||||
|
||||
console.log(
|
||||
`[generator ${id}] ready with ${session.openedConnections} connections to ${stdbUrl}/${moduleName}`,
|
||||
`[generator ${id}] ready with ${session.openedConnections} connections to ${stdbUrl}/${moduleName} compression=${stdbCompression}`,
|
||||
);
|
||||
|
||||
while (!stopping) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
defaultBenchTestName,
|
||||
defaultDemoSystems,
|
||||
getSharedRuntimeDefaults,
|
||||
parseStdbCompression,
|
||||
parseConnectorList,
|
||||
type BenchOptions,
|
||||
type ConcurrencyTests,
|
||||
@@ -151,6 +152,11 @@ function addSharedRuntimeOptions(parser: CLIParser): CLIParser {
|
||||
.option('--stdb-url <url>', 'SpacetimeDB url', str())
|
||||
.option('--stdb-module <name>', 'SpacetimeDB module name', str())
|
||||
.option('--stdb-module-path <dir>', 'SpacetimeDB module path', str())
|
||||
.option(
|
||||
'--stdb-compression <mode>',
|
||||
'SpacetimeDB client compression mode (`none` or `gzip`)',
|
||||
str(),
|
||||
)
|
||||
.option('--no-stdb-confirmed-reads', 'Disable confirmed reads')
|
||||
.option('--use-docker', 'Use docker')
|
||||
.option('--no-use-spacetime-metrics-endpoint', '')
|
||||
@@ -187,6 +193,10 @@ function resolveRuntimeOptions(
|
||||
stdbUrl: normalizeStdbUrl(options.stdbUrl ?? defaults.stdbUrl),
|
||||
stdbModule: options.stdbModule ?? defaults.stdbModule,
|
||||
stdbModulePath: options.stdbModulePath ?? defaults.stdbModulePath,
|
||||
stdbCompression: parseStdbCompression(
|
||||
options.stdbCompression ?? defaults.stdbCompression,
|
||||
'--stdb-compression',
|
||||
),
|
||||
stdbConfirmedReads:
|
||||
options.stdbConfirmedReads ?? defaults.stdbConfirmedReads,
|
||||
useDocker: options.useDocker ?? defaults.useDocker,
|
||||
|
||||
Reference in New Issue
Block a user