Skip to content
rustle

Benchmarks: rustle against 3proxy, Squid, gost and Tinyproxy

Every number published by the project, with the hardware, the versions, the tuning and the limits that go with it. One campaign, 2026-10-28.

How it was measured

Auth on, one proxy core and one worker for every proxy, shuffled test order, proxy restarted before each test, warmup run apart, median of the repeats, concurrency sweep per test (best clean level kept, at_conns).

Proxy under test
EM-I320E-NVMe, AMD EPYC 8224P
Load generator
EM-I320E-NVMe, AMD EPYC 8224P
Origin and sink
EM-I220E-NVMe, AMD EPYC 8124P
Network
25 Gbit/s Private Network (VLAN on the NIC), 25 Gbit/s nominal, 23.5Gbit/s measured
Runs
3 repeats of 15 s, medians, seed 2004113323, noise about ±3 to 5 %
Proxy cores and authentication
1 core, authentication on

Versions and tuning

  • rustle 1.0.0

    cargo build --locked --release (LTO, no target-cpu, Cargo.lock: as in release.yml)

    • socket_buffer_bytes = 1048576 (set in the bench config; the shipped default is 0, kernel autotuning)

    Source repository of rustle

  • 3proxy 1.0.0

    from source, Makefile.Linux

    • proxy -a -osTCP_NODELAY -ocTCP_NODELAY (documented for small exchanges; -a = no Forwarded header, like the others)
    • maxconn, nscache, timeouts

    Source repository of 3proxy

  • Squid 7.7

    from source, upstream's default flags, OpenSSL

    • cache deny all, cache_mem 0
    • tcp_recv_bufsize 1 MB, read_ahead_gap 1 MB
    • forwarded_for delete, via off
    • auth helper results cached 2 h
    • workers N for N cores
    • http_upgrade_request_protocols WebSocket and websocket allow all (authentication stays enforced by http_access)

    Source repository of Squid

  • gost 3.3.0

    official image

    • GOGC=400
    • logger level error (GOST_LOGGER_LEVEL=error)
    • Go sizes GOMAXPROCS from the cpuset
  • Tinyproxy 1.11.3

    from source

    • MaxClients 200000
    • LogLevel Critical
    • no Via, no filters

    Source repository of Tinyproxy

Results

Best clean concurrency level of each proxy, median of 3 runs. “—” means the proxy does not support that mode. 1 core per proxy · authentication on · Scaleway Elastic Metal, Paris, AMD EPYC 8224P · 25 Gbit/s private network (23.5 measured) · median of 3 runs · seed 2004113323 · campaign of 2026-10-28.

Plain HTTP proxy port

Plain HTTP proxy port: measured values by proxy
TestUnitrustle3proxySquidgostTinyproxy
HTTP, 1 KB responsesreq/s55,25821,03215,1404,7557,580
HTTP, 10 KB responsesreq/s40,78319,16910,8144,4365,669
HTTP, 1 KB responses, a new connection per requestreq/s27,8275,1327,8044,7807,584
HTTP, 1 MB responsesreq/s2,6241,7843531,046199
HTTP, 10 MB responsesreq/s2681913314521
CONNECT tunnels, bulk transferGbit/s22.015.713.613.21.8
CPU cost per request (1 KB)µs/req18.147.666.0210.0129.4
Memory with 1,000 open tunnelsMB1410415016118
Memory with 5,000 open tunnelsMB4049927565361
Memory with 10,000 open tunnelsMB549924321,243115
Memory with 25,000 open tunnelsMB952,4619123,228274

HTTPS proxy (resumed TLS sessions)

HTTPS proxy (resumed TLS sessions): measured values by proxy
TestUnitrustle3proxySquidgostTinyproxy
HTTP, 1 KB responsesreq/s49,461—13,5092,528—
HTTP, 10 KB responsesreq/s35,460—9,3412,433—
HTTP, 1 KB responses, a new connection per requestreq/s6,119—2,0472,516—
HTTP, 1 MB responsesreq/s1,297—277615—
HTTP, 10 MB responsesreq/s142—2783—
CONNECT tunnels, bulk transferGbit/s12.0—4.97.1—
Memory with 1,000 open tunnelsMB57—181240—
Memory with 5,000 open tunnelsMB253—432903—
Memory with 10,000 open tunnelsMB466—7602,110—
Memory with 25,000 open tunnelsMB810—2,5844,094—

HTTPS proxy, full handshake on every connection

HTTPS proxy, full handshake on every connection: measured values by proxy
TestUnitrustle3proxySquidgostTinyproxy
HTTP, 1 KB responses, a new connection per request, full handshakereq/s5,458—1,9222,246—

HTTP/2 over TLS

HTTP/2 over TLS: measured values by proxy
TestUnitrustle3proxySquidgostTinyproxy
HTTP, 1 KB responsesreq/s33,451——5,231—
HTTP, 10 KB responsesreq/s24,789——4,732—
HTTP, 1 KB responses, a new connection per requestreq/s4,974——2,187—
HTTP, 1 MB responsesreq/s860——447—
HTTP, 10 MB responsesreq/s88——50—
CONNECT tunnels, bulk transferGbit/s8.8——7.8—
Memory with 1,000 open tunnelsMB70——225—
Memory with 5,000 open tunnelsMB330——1,245—
Memory with 10,000 open tunnelsMB705——2,639—
Memory with 25,000 open tunnelsMB1,263——5,884—

WebSocket, plain

WebSocket, plain: measured values by proxy
TestUnitrustle3proxySquidgostTinyproxy
WebSocket, 64-byte messagesmsg/s58,50633,13643,71046,808—
WebSocket round trip, 64-byte messages (p99)ms1.33.21.52.6—
CPU cost per WebSocket messageµs/msg17.130.222.921.4—
WebSocket, 64 KB messagesGbit/s11.67.96.66.9—
WebSocket, one connection per exchangemsg/s10,7402514,8793,726—

WebSocket over TLS

WebSocket over TLS: measured values by proxy
TestUnitrustle3proxySquidgostTinyproxy
WebSocket, 64-byte messagesmsg/s56,955—36,78644,426—
WebSocket round trip, 64-byte messages (p99)ms1.3—1.82.7—
WebSocket, 64 KB messagesGbit/s5.8—2.43.8—
WebSocket, one connection per exchangemsg/s4,462—1,7552,190—

More cores

Plain HTTP, 1 KB responses, 1 to 8 proxy cores

Plain HTTP, 1 KB responses, 1 to 8 proxy cores: req/s by number of proxy cores
Proxy coresrustle3proxySquidgostTinyproxy
155,27521,10615,0944,785—
2111,58734,38129,5689,178—
4218,92267,39059,41817,677—
8439,741114,736116,83431,011—

Same hosts, seed and protocol as the single-core matrix, one test (http-1kb), connection levels 64, 256, 1,024 and 4,096, best clean level kept. The proxy gets n physical cores and n workers.

Kernel TLS is slower

tls.ktls is opt-in and off by default. Software kernel TLS saves 5 % to 20 % of memory, but is slower than the default rustls path on every throughput test, by 12 % to 43 %. One core, no NIC TLS offload.

rustls against software kernel TLS, by test
TestUnitrustls (default)Kernel TLSChange
HTTP, 1 KB responsesreq/s49,46143,422-12.2 %
HTTP, 10 KB responsesreq/s35,46031,154-12.1 %
HTTP, 1 KB responses, a new connection per requestreq/s6,1195,158-15.7 %
HTTP, 1 MB responsesreq/s1,297896-30.9 %
HTTP, 10 MB responsesreq/s14289-37.1 %
CONNECT tunnels, bulk transferGbit/s12.06.9-43.0 %
Memory with 1,000 open tunnelsMB5754-5.2 %
Memory with 5,000 open tunnelsMB253228-9.9 %
Memory with 10,000 open tunnelsMB466372-20.3 %
Memory with 25,000 open tunnelsMB810753-7.0 %

What these numbers do not show

  • The origin is static with Content-Length. Chunked bodies, uploads, SOCKS5, IPv6, many origins and large header sets are not part of the matrix; they are covered functionally by the end-to-end suite.
  • One campaign, one seed, three repeats, medians, noise about ±3 to 5 %, no confidence intervals. Differences below the noise are not conclusions.
  • Latency is closed-loop at each concurrency level (no open-loop rate); CPU per request is measured with the proxy fully loaded, not at the same request rate for every proxy.
  • The test network can carry about 23.5 Gbit/s (25 nominal). Where rustle gets close to it (1 MB and 10 MB responses, plain tunnels), the network sets the number, not rustle: rustle's real figure, and its real lead, are higher than the one shown.
  • There is no splice on a TLS port (the proxy decrypts in user space), so TLS and HTTP/2 throughput is lower than plain HTTP.
  • The HTTP/2 test opens one connection per client connection and sends sequential requests (no multiplexing).
  • Multi-core was measured for plain HTTP at 1 KB only; TLS, HTTP/2 and tunnels were not measured on several cores.
  • Proxy CPU is the container cgroup's (user + system); softirq time spent on other cores is not attributed.
  • The tunnel test counts bytes written by the client and measures the upload direction only.

The raw runs, the harness and the procedure are in the benchmarks directory of the proxy repository.