HTTP (L7) proxy benchmark · open-loop ramp · c1k-tls

request throughput 20261007-024759

Every proxy driven through the identical linear ramp (zrk, open-loop, coordinated-omission corrected) at 1000 connections. Throughput and CPU span the full ramp. The table's p50 / p99 are each proxy's latency at a common 2k req/s reference load — a shared, light, sub-knee rate where the number reflects per-request cost rather than queueing. The load is offered over TLS 1.3, terminated by the proxy; every proxy's upstream leg stays plaintext, as zoxy terminates inbound only. All five load the same self-signed ECDSA P-256 certificate — the key type is part of the measurement, since the signature is per handshake. The generator offers no ALPN (so this is HTTP/1.1, like every other profile) and never resumes a session, so each connection pays a full handshake at connect time and the steady state read below is record-layer crypto on kept-alive connections, not handshake throughput. The cipher suite is each proxy's own choice from what the generator offers — AES-GCM and ChaCha20-Poly1305 do not cost the same per byte, and only some of these proxies expose a knob for it, so it is recorded as part of "the proxy as it ships" rather than pinned.

proxymax sustained req/sp50 @ 2kp99 @ 2kpeak memstatus
zoxy0.9.0 @935a2f34946.68k0.37ms0.88ms352.6MiBok
nginx1.3116.765k0.40ms0.92ms80.7MiBok
haproxy3.4.615.7984k0.40ms1.39ms115.1MiBok
pingora0.810.8172k0.42ms1.36ms89.4MiBok
envoy—9.1645k0.56ms1.85ms82.2MiBok

Successful req/s vs offered

open-loop ramp; dashed gray = perfect keep-up

010k20k30k40k50k010k20k30k40k50koffered load (req/s)req/s

Proxy CPU vs offered

container cores sampled from cAdvisor at 1Hz, on the ramp's own clock

00.250.50.7511.3010k20k30k40k50koffered load (req/s)cores

p99 latency vs offered (while keeping up)

per-window tail (log scale); each line stops where that proxy stops keeping up

1101001k10k010k20k30k40k50koffered load (req/s)ms

Load shed vs offered

offered load the proxy couldn't serve (1 − achieved/offered); the first few seconds include the generator's own ramp-up shortfall, which is not the proxy's

0%20%40%60%80%100%010k20k30k40k50koffered load (req/s)

Latency distribution · HdrHistogram (whole run)

zoxy

latency by percentile · raw zoxy.hgrm

020k40k60kp0p90p99p99.9p99.99p99.99900000000001p99.9999p99.99999000000001percentilems

haproxy

latency by percentile · saturated at 60s — tail percentiles are a floor, not a value · raw haproxy.hgrm

020k40k60k80kp0p90p99p99.9p99.99p99.99900000000001p99.9999p99.99999000000001percentilems

nginx

latency by percentile · saturated at 60s — tail percentiles are a floor, not a value · raw nginx.hgrm

020k40k60k80kp0p90p99p99.9p99.99p99.99900000000001p99.9999p99.99999000000001percentilems

pingora

latency by percentile · saturated at 60s — tail percentiles are a floor, not a value · raw pingora.hgrm

020k40k60k80kp0p90p99p99.9p99.99p99.99900000000001p99.9999p99.99999000000001percentilems

envoy

latency by percentile · saturated at 60s — tail percentiles are a floor, not a value · raw envoy.hgrm

020k40k60k80kp0p90p99p99.9p99.99p99.99900000000001p99.9999p99.99999000000001percentilems