Something went wrong. Try again.
Demo comparing html-over-the-wire w/ WS and SSE.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100// Test 1 — what does it cost to just HOLD a connection open?//// No latency proxy: RTT is irrelevant to steady-state memory, and the proxy// would add its own footprint to the measurement.
import { startServer, sleep, table, fmtBytes } from './lib.js'import { createClient } from '../src/client.js'
// Capped by the host's ephemeral port range, not by the server: client and// server share 127.0.0.1's ~16k ports here. Per-connection cost is linear, so// these extrapolate.const COUNTS = (process.env.COUNTS ?? '1000,4000').split(',').map(Number)const HOLD_MS = Number(process.env.HOLD_MS ?? 4000)
const VARIANTS = [ { name: 'ws (plain)', arch: 'ws', tls: false }, { name: 'ws (tls)', arch: 'ws', tls: true }, { name: 'sse h2 (plain)', arch: 'sse', tls: false }, { name: 'sse h2 (tls)', arch: 'sse', tls: true }, { name: 'sse h1 (plain)', arch: 'sse', tls: false, h1: true },]
const results = []
for (const v of VARIANTS) { for (const count of COUNTS) { try { const server = await startServer({ ...v, compress: 'none' }) await sleep(300) await server.reset() const base = await server.stats()
const clients = [] const t0 = performance.now() // Connect in waves so we don't just measure accept-queue backpressure. const WAVE = 200 for (let i = 0; i < count; i += WAVE) { const batch = [] for (let j = i; j < Math.min(i + WAVE, count); j++) { const c = createClient({ arch: v.arch, h1: v.h1, host: '127.0.0.1', port: server.port, tls: v.tls, room: String(j), compress: 'none', }) clients.push(c) batch.push(c.connect().catch((e) => ({ err: e.message }))) } await Promise.all(batch) } const connectMs = performance.now() - t0
await sleep(HOLD_MS) const after = await server.stats()
const connected = after.subscribers results.push({ variant: v.name, target: count, connected, rssPer: connected ? (after.rss - base.rss) / connected : NaN, heapPer: connected ? (after.heapUsed - base.heapUsed) / connected : NaN, extPer: connected ? (after.external - base.external) / connected : NaN, rssTotal: after.rss - base.rss, connectRate: Math.round(connected / (connectMs / 1000)), // CPU burned while doing nothing but holding sockets open. idleCpuMs: +(after.cpuUserMs + after.cpuSystemMs).toFixed(1), })
for (const c of clients) c.close() await server.stop() // Let TIME_WAIT drain before the next variant claims the same ports. await sleep(2000) console.error(` done ${v.name} @ ${count} (${connected} connected)`) } catch (e) { console.error(` SKIP ${v.name} @ ${count}: ${e.message}`) await sleep(3000) } }}
console.log('\n=== Test 1: idle connection cost ===\n')console.log( table(results, [ { label: 'variant', get: (r) => r.variant }, { label: 'conns', get: (r) => r.connected }, { label: 'RSS total', get: (r) => fmtBytes(r.rssTotal) }, { label: 'RSS/conn', get: (r) => fmtBytes(Math.round(r.rssPer)) }, { label: 'heap/conn', get: (r) => fmtBytes(Math.round(r.heapPer)) }, { label: 'ext/conn', get: (r) => fmtBytes(Math.round(r.extPer)) }, { label: 'conn/s', get: (r) => r.connectRate }, { label: 'idle CPU', get: (r) => `${r.idleCpuMs} ms` }, ]),)
console.log('\n' + JSON.stringify({ test: 'idle', results }))