Comparison

Busbar vs Bifrost

Bifrost is a real, working Go gateway, and we tested it fairly: the identical benchmark on both, same machine, same method, the same 2-to-16 core sweep, each driven with unique request traffic so every request is real proxy work. Both scale linearly with cores. But Busbar sustains about 9× the throughput per core on identical real-proxy traffic, and under sustained large-payload load Bifrost's memory runs away into an OOM while Busbar stays bounded. Where Bifrost is good, we say so; where its own published numbers didn't reproduce, we show our work.

The benchmark we ran (both setups identical)

One c7g.8xlarge (32 vCPU Graviton3) (Graviton has no hyperthreading, so one vCPU is one real core — honest per-core scaling). The gateway under test is pinned to N cores; a dedicated load generator and a fast mock upstream get their own cores, so the gateway is never starved and the mock (~250k req/s ceiling) is never the bottleneck. Critically, every request carries a unique body — identical bodies let a gateway cache and answer without proxying, which inflates throughput past what the upstream can even serve. We swept both gateways 2 → 16 cores and recorded req/s at 100% success.

Throughput scales linearly — for both

050k100k150k 246810121416 CPU cores → req/s 2 cores · Bifrost 2,936 req/s4 cores · Bifrost 5,569 req/s6 cores · Bifrost 8,236 req/s8 cores · Bifrost 11,042 req/s10 cores · Bifrost 13,869 req/s12 cores · Bifrost 15,887 req/s14 cores · Bifrost 17,294 req/s16 cores · Bifrost 18,346 req/s 2 cores · Busbar 19,838 req/s · 37 µs added latency p994 cores · Busbar 38,285 req/s · 33 µs added latency p996 cores · Busbar 61,505 req/s · 34 µs added latency p998 cores · Busbar 83,850 req/s · 32 µs added latency p9910 cores · Busbar 101,853 req/s · 33 µs added latency p9912 cores · Busbar 120,038 req/s · 33 µs added latency p9914 cores · Busbar 142,038 req/s · 33 µs added latency p9916 cores · Busbar 156,223 req/s · 33 µs added latency p99 Busbar 156k ~9,750 req/s per core Bifrost 18k ~1,147 req/s per core
req/s at 100% success vs cores, same box, real proxy traffic. Both lines are straight — Busbar at ~9750+ req/s per core, Bifrost at ~1,147. Hover any point for its numbers.

Head-to-head at 16 cores

BusbarBifrost
Throughput (16 cores, 100% success) 156,223 req/s 18,346 req/s ~9× less
Per core ~9,750 req/s ~1,147 req/s ~9× less
Added latency, p99 its own overhead ~33 µs flat, in-band on every response claimed 11 µs measured ~1.4 ms ~42× slower see below
Memory under load 150 KB bodies, sustained ~1.2 GB plateaus, falls to idle ~19 GB ~15× more, never released
Scales with cores? Yes — linearly Yes — linearly

Both scale linearly on one box, so this isn't "Bifrost can't scale." It's that it doesn't scale nearly as well. On identical 16 cores Busbar carries 156,223 req/s to Bifrost's 18,346, about 9× the throughput. Matching Busbar takes ~9× the cores (or 9× the machines). And under real large-payload load the memory gap is far wider still, which is the next section.

Memory: a bounded plateau vs a sawtooth that never comes down

Bifrost publishes a 3.34 GB peak-memory figure from its own benchmark. A short, small-payload run never reproduces it (the pools don't fill, and a snapshot right after boot reads ~150 MB), so we filled the pools the way their big-payload benchmark does: unique 150 KB request bodies, 1,500 concurrent, held for minutes, sampling resident memory throughout. Same box, same mock, Bifrost on its own documented pool config (initial_pool_size 15000, buffer_size 20000) against Busbar 1.4.0.

05101520 GB 060120180240300360 seconds (load stops at 300s) → Bifrost's own published peak: 3.34 GB Bifrost ~19 GB, sawtooth, never released Busbar ~1.2 GB falls to idle
Resident memory under sustained 150 KB load, same box. Bifrost's pooled buffers jump to a ~19 GB sawtooth (Go GC), well above its own published 3.34 GB (dashed). The load stops at 300s: Busbar returns to ~252 MB within ~30s; Bifrost holds its pools. (Bifrost's line is measured to 222s, then held flat, since its footprint doesn't shrink.)

Two different behaviours. Busbar's memory is a bounded working set: it holds a few copies of each in-flight request body, so peak tracks concurrency × payload and a completed request frees its buffers. The same 150 KB payload at concurrency 200 uses only ~140 MB. Busbar 1.4.0 runs on jemalloc with a background purge thread, so when the load stops the pages go back to the OS and RSS falls to ~252 MB.

Bifrost's memory is its pools. They fill under load, sawtooth on Go's GC at ~19 GB (about 15× Busbar, and already ~5× their own published 3.34 GB), and they don't come back when the load stops. It also scales with payload: at 400 KB bodies it held ~43 GB, and at 300 KB with 2,500 concurrent it climbed past 45 GB and, still rising, OOM-killed the 61 GB box out from under itself.

One caveat, stated plainly, because it's the fair question to ask: we tested Bifrost on its documented pool config (initial_pool_size 15000, buffer_size 20000) — the same settings behind its own published 3.34 GB figure — not on a memory-minimized tuning. Bifrost does expose pool-sizing knobs, and smaller values would cap the ceiling lower; that's a real lever a production deployment could pull. But two things don't change with it: the config Bifrost itself ships and benchmarks already balloons well past its own published number, and the underlying behaviour is a retained pool on Go's GC — turning the knob down trades burst headroom for a lower cap, it doesn't make the memory a bounded, self-releasing working set the way Busbar's is. The full harness and raw CSVs are in bench/memory/ — retune it yourself and the shape holds.

Their "11 µs" — and what we actually measured

Where Bifrost is genuinely good

Methodology

One c7g.8xlarge (32 vCPU Graviton3), unique request bodies (real proxy, no cache); gateway pinned to N cores; DEDICATED 12-core load gen + 4-core mock so the gateway is never starved. Busbar 1.4.1 and Bifrost 1.6.4. Raw per-core CSVs and the load generator are archived with the site under bench/; the full method (and every gotcha) is in the benchmark runbook. Re-run it and you'll get the same shape. Measured 2026-07-19.