Files
amethyst/quartz-relay
Claude d49d4a1025 perf(relay): load benchmark + bump per-session outbound buffer
Adds an opt-in load benchmark suite (`-DrunLoadBenchmark=true`)
covering: held-open WebSocket count, single + concurrent EVENT
publish throughput, and live-event fan-out latency to N
subscribers on one connection.

Numbers from a small VM (4 GiB RAM, 4 vCPU, ulimit -n 4096):

  Connections (raw WS, one REQ each)
    100   :  100 OK, 0.7 s
    500   :  500 OK, 1.2 s
    1000  : 1000 OK, 2.0 s
    2000  : 1993 OK (hits the 4096-fd ceiling: 2 fds per WS)

  Single-publisher serial publish + OK
    10000 events, 13.2 s, 760 EPS (round-trip latency bound)

  Concurrent publishers (each on its own WS)
    parallel=2  :  807 EPS
    parallel=4  : 1452 EPS
    parallel=8  : 1989 EPS  ← knee
    parallel=16 : 1704 EPS  ← SQLite single-writer ceiling
    parallel=32 : 1778 EPS

  Fanout (one publish, N active subs on a single WS)
    100 subs  : 67 ms last
    500 subs  : 52 ms last
    1000 subs : 51 ms last
    2000 subs : 111 ms last

Bumped SESSION_OUTGOING_BUFFER from 1024 → 8192. The 1024 cap was
hit by the 2000-sub fanout test (2000 outbound frames into one
session's queue), causing the relay to drop the connection as a
slow-consumer protection. 8192 fits the realistic upper bound for
a high-fan-out client (a few thousand subs on one WS) and caps
per-session memory at ~2 MiB before we drop.

Numbers also confirm:
  - The SQLite single-writer plateau is around 2000 EPS on this
    box. Production behind WAL + a faster disk should beat that.
  - Each WebSocket consumes 2 file descriptors. Operators must
    raise `ulimit -n` to ~3× their target connection count.
  - Fan-out scales sub-linearly (2000 subs ≈ 2× the latency of
    100 subs) — the bottleneck is shared (broadcast + SQLite
    write), not per-sub.

Total :quartz-relay tests: 99 (4 new benchmarks, opt-in), 0 failures.
2026-05-07 03:41:49 +00:00
..