Latest public benchmark

Serious load, measured in public.

A single small VM pushed through heavy HTTPS concurrency with CPU, memory, latency, clean-response behavior, and raw rows published for inspection.

TLDR: Tako stayed clean through c20000 on a small exe.dev VM while doing app-aware routing, limiter accounting, forwarding headers, and instance selection.

largest run
c20000
non-200
0
client errors
0
Benchmark VM exe.dev, Tokyo

Load generator, proxy, and app all share this host.

CPU 2 vCPU

AMD EPYC 9554P on KVM.

Memory 7.8 GiB RAM

No swap configured.

OS Ubuntu 24.04.4

Linux 6.12.90.

Tako at c5000 12.5k clean 200 RPS

0 non-200, 0 client errors.

Tako at c20000 7.3k clean 200 RPS

Stable at the largest tested HTTP concurrency.

Clean through c20000 all 200 responses

0 client errors in every heavy Tako row.

Features clean through c4000

Channels and workflows both stay clean through c4000.

Proxy comparison

Raw HTTPS proxy path#

Same route, same self-signed TLS certificate, same upstream application, same benchmark VM. The heavy rows show the real capacity of one small VM when load generator, proxy, and app all share two vCPUs.

throughput

HTTP 200 RPS by concurrency

Tako stays clean at high concurrency and beats Caddy and Envoy across the heavy rows. nginx and HAProxy show the static-proxy ceiling for this VM.

0 5k 10k 15k 20k c1k c2.5k c5k c7.5k c10k c15k c20k nginx c1000: 21k nginx c2500: 19k nginx c5000: 18k nginx c7500: 16k nginx c10000: 15k nginx c15000: 11k nginx c20000: 11k HAProxy c1000: 21k HAProxy c2500: 18k HAProxy c5000: 17k HAProxy c7500: 16k HAProxy c10000: 15k HAProxy c15000: 13k HAProxy c20000: 11k Tako c1000: 15k Tako c2500: 14k Tako c5000: 13k Tako c7500: 12k Tako c10000: 10k Tako c15000: 8.6k Tako c20000: 7.3k Envoy c1000: 12k Envoy c2500: 12k Envoy c5000: 4.7k Envoy c7500: 4.3k Envoy c10000: 3.7k Envoy c15000: 3.8k Envoy c20000: 828 Caddy c1000: 6.6k Caddy c2500: 5.9k Caddy c5000: 5.2k Caddy c7500: 4.8k Caddy c10000: 1.7k Caddy c15000: 1.7k Caddy c20000: 1.3k
  • nginx
  • HAProxy
  • Tako
  • Envoy
  • Caddy

tail latency

p99 latency by concurrency

Tako completes every high-load row cleanly, with tail latency published beside RPS so the tradeoff stays visible. nginx is the tightest p99 reference in this run.

0ms 5s 10s 15s 20s 25s c1k c2.5k c5k c7.5k c10k c15k c20k nginx c1000: 100ms nginx c2500: 315ms nginx c5000: 1.1s nginx c7500: 1.9s nginx c10000: 1.2s nginx c15000: 6.1s nginx c20000: 3.8s HAProxy c1000: 103ms HAProxy c2500: 278ms HAProxy c5000: 1.5s HAProxy c7500: 3.5s HAProxy c10000: 6.4s HAProxy c15000: 13s HAProxy c20000: 16s Tako c1000: 154ms Tako c2500: 527ms Tako c5000: 2.4s Tako c7500: 5.1s Tako c10000: 7s Tako c15000: 12s Tako c20000: 16s Envoy c1000: 145ms Envoy c2500: 374ms Envoy c5000: 3.1s Envoy c7500: 4.8s Envoy c10000: 6.7s Envoy c15000: 14s Envoy c20000: 27s Caddy c1000: 260ms Caddy c2500: 2.3s Caddy c5000: 5.2s Caddy c7500: 8.9s Caddy c10000: 20s Caddy c15000: 24s Caddy c20000: 26s
  • nginx
  • HAProxy
  • Tako
  • Envoy
  • Caddy

errors

Clean-run behavior by concurrency

The line combines non-200 responses and client-side errors, so lower is better. Tako remains at 0% through c20000 on this run.

0% 10% 20% 30% 40% c1k c2.5k c5k c7.5k c10k c15k c20k nginx c1000: 0% nginx c2500: 0% nginx c5000: 0% nginx c7500: 0% nginx c10000: 0% nginx c15000: 0.15% nginx c20000: 0% HAProxy c1000: 0% HAProxy c2500: 0% HAProxy c5000: 0% HAProxy c7500: 0% HAProxy c10000: 0% HAProxy c15000: 0% HAProxy c20000: 0% Tako c1000: 0% Tako c2500: 0% Tako c5000: 0% Tako c7500: 0% Tako c10000: 0% Tako c15000: 0% Tako c20000: 0% Envoy c1000: 0% Envoy c2500: 0% Envoy c5000: 0.28% Envoy c7500: 1.06% Envoy c10000: 3.55% Envoy c15000: 39.19% Envoy c20000: 41.3% Caddy c1000: 0% Caddy c2500: 0% Caddy c5000: 0.14% Caddy c7500: 0.39% Caddy c10000: 0.06% Caddy c15000: 4.75% Caddy c20000: 7.51%
  • nginx
  • HAProxy
  • Tako
  • Envoy
  • Caddy

memory

Proxy memory by concurrency

Memory is published beside throughput so connection cost stays visible. The high-concurrency Tako rows include Pingora/TLS keepalive state from live downstream connections.

0MiB 700MiB 1.4GiB 2.1GiB 2.7GiB c1k c2.5k c5k c7.5k c10k c15k c20k nginx c1000: 66MiB nginx c2500: 114MiB nginx c5000: 220MiB nginx c7500: 216MiB nginx c10000: 221MiB nginx c15000: 389MiB nginx c20000: 262MiB HAProxy c1000: 71MiB HAProxy c2500: 140MiB HAProxy c5000: 265MiB HAProxy c7500: 275MiB HAProxy c10000: 476MiB HAProxy c15000: 580MiB HAProxy c20000: 896MiB Tako c1000: 195MiB Tako c2500: 387MiB Tako c5000: 748MiB Tako c7500: 998MiB Tako c10000: 1.3GiB Tako c15000: 1.9GiB Tako c20000: 2.7GiB Envoy c1000: 125MiB Envoy c2500: 208MiB Envoy c5000: 336MiB Envoy c7500: 450MiB Envoy c10000: 560MiB Envoy c15000: 779MiB Envoy c20000: 999MiB Caddy c1000: 215MiB Caddy c2500: 389MiB Caddy c5000: 623MiB Caddy c7500: 908MiB Caddy c10000: 1.2GiB Caddy c15000: 1.4GiB Caddy c20000: 1.5GiB
  • nginx
  • HAProxy
  • Tako
  • Envoy
  • Caddy
Heavy rows, clean 200 RPS and sampled resources
proxy c5000 c10000 c20000 c20000 p99 proxy RSS readout
nginx 17.7k 15.3k 11.0k 3.8s 262 MiB Static-proxy RPS reference
HAProxy 17.1k 14.8k 11.2k 15.7s 896 MiB High RPS, wider p99
Tako 12.5k 10.4k 7.3k 15.5s 2.7 GiB Clean through c20000
Envoy 4.7k 3.7k 0.8k 26.6s 999 MiB High-load pressure
Caddy 5.2k 1.7k 1.3k 26.4s 1.5 GiB High-load pressure

Channels and workflows

Built-in feature paths, measured separately#

These rows exercise more than the proxy. The app uses the JavaScript SDK, publishes durable channel messages, and enqueues workflows with persisted steps while everything shares the same 2 vCPU budget.

built-in features

Channels and workflows 200 RPS

Both feature paths stay clean through c4000 on the same 2 vCPU VM, while still using the SDK, SQLite-backed persistence, and the proxy path.

0 2k 4k 6k c500 c1k c2k c4k c8k Channel publish c500: 7.2k Channel publish c1000: 6.8k Channel publish c2000: 6.4k Channel publish c4000: 5.9k Channel publish c8000: 4.1k Workflow enqueue c500: 5.7k Workflow enqueue c1000: 5.4k Workflow enqueue c2000: 5.2k Workflow enqueue c4000: 4.8k Workflow enqueue c8000: 1.9k
  • Channel publish
  • Workflow enqueue

feature tail latency

Channels and workflows p99 latency

Workflow enqueue persists steps, so it naturally carries more work than channel publish. Both paths stay clean through c4000 in this single-instance run.

0ms 3s 6s 9s c500 c1k c2k c4k c8k Channel publish c500: 127ms Channel publish c1000: 261ms Channel publish c2000: 800ms Channel publish c4000: 2.8s Channel publish c8000: 6.7s Workflow enqueue c500: 171ms Workflow enqueue c1000: 387ms Workflow enqueue c2000: 1.2s Workflow enqueue c4000: 3.6s Workflow enqueue c8000: 8.4s
  • Channel publish
  • Workflow enqueue

What it means

App-aware routing under load.#

Tako stayed clean while doing product work a static reverse proxy does not need to do: route lookup, source IP derivation, per-client limiter accounting, app and instance selection, in-flight accounting, upstream peer construction, and forwarding header normalization.

The report still keeps static proxy references, p99, memory, and clean-run percentages in view because those are the tuning levers. Future runs can isolate larger-VM behavior, external same-region load generation, and narrower Pingora session and upstream-proxy costs under 10k to 20k live TLS connections.

Method

Same conditions, public raw data.#

The public report intentionally omits hostnames, public IPs, private network addresses, peer names, and user identifiers.

HTTP path

Load generator, proxy, and app all run on the VM. The route is bench.test:18443, resolved to loopback, with Host and SNI set to bench.test.

Proxy matrix

Tako tako-server 0.0.0-09b3dc6, nginx 1.24.0, HAProxy 2.8.16, Envoy 1.38.0, Caddy 2.11.3 with rate limiting.

Timing

10 second warmup, 30 second measurement window, HTTP/1.1 over TLS, 60 second request timeout, metrics sampled from /proc once per second.