simoom / Benchmarks
Benchmarks · campaign 4 · measured 2026-11-12
simoom against 20 servers, use case by use case
The servers a team would otherwise pick, from hyper, axum and actix-web to nginx, Go, Netty and Kestrel, each measured on the same droplet as simoom, with the same load machines, in the same round. Every chart and ratio on this page is generated from the raw records. The losses are in the same charts as the wins.
simoom against the field, use case by use case
Campaign 4: simoom and 20 other servers, each measured on the same DigitalOcean droplet as simoom, with the same load machines, in the same round; three rounds on three droplets. Every bar is relative to simoom on that droplet, so no comparison mixes machines. Losses are in the same charts as wins.
Health checks and status endpoints
A small GET answered from memory: load-balancer probes, status pages, the busiest route of most APIs.
Behind may-minihttp: 6% more than simoom Status endpoint, 256 clients: requests/s with 99% within 1 ms; ahead of 16 of 18, level with 1; behind may-minihttpJSON APIs
A 1 KB JSON body in, a 1 KB JSON body out, the shape of most service calls.
Behind may-minihttp: 5% more than simoom JSON API, 1 KB in and out, 256 clients: requests/s with 99% within 1 ms; ahead of 10 of 11; behind may-minihttpHTTPS APIs and new TLS clients
The same API over TLS 1.3, and how many new and returning clients the handshake can take per second.
First of 8: simoom 30% more than the next best, axum + rustls HTTPS API, 256 clients: requests/s with 99% within 1 ms; ahead of 7 of 7Clients that connect for every request
Serverless callers, scripts and devices that open a connection, send one request and close it.
Behind xitca-web: 29% more than simoom A new connection per request, 192 clients: requests/s with 99% within 5 ms; ahead of 12 of 18, level with 2; behind xitca-web, Cameleer's old server, actix-web, may-minihttpService-to-service HTTP/2
64 connections with 100 streams each, as gRPC and service meshes use HTTP/2.
Behind H2O: 11% more than simoom Service-to-service HTTP/2, 64 connections x 100 streams: requests/s with 99% within 5 ms; ahead of 9 of 11, level with 1; behind H2OMobile clients over HTTP/3
QUIC instead of TCP, for clients on lossy or changing networks.
Behind H2O: 43% more than simoom HTTP/3, 64 clients: requests/s with 99% within 1 ms; ahead of 2 of 3; behind H2ODownloads
64 KB responses; 1 MB responses fill the network card for every server.
Level with the best, actix-web 64 KB downloads, 64 clients: requests/s with 99% within 5 ms; ahead of 0 of 7, level with 7Many idle connections
Devices and push clients that stay connected and mostly say nothing.
Behind nginx: 6% less than simoom 10,000 idle connections: memory per connection; ahead of 17 of 18; behind nginxTraffic spikes
195,000 requests per second offered, more than the network card can carry.
Behind actix-web: 22x more than simoom Traffic spike at 195,000 requests/s offered: answers within 1 ms per second; ahead of 9 of 18; behind actix-web, nginx, xitca-web, uWebSockets.js, Vert.x (Java), HAProxy, ntex, Netty (Java), fasthttp (Go)Slow attackers
Real requests while 10,000 slowloris and 1,000 slow-read connections press.
Behind Go net/http: 44% lower than simoom Under 11,000 slow attackers: p99 of real requests; ahead of 10 of 18, level with 3; behind Go net/http, HAProxy, Vert.x (Java), Netty (Java), H2OStart-up, size and memory
What a server costs before and while it answers.
First of 21: simoom 57% faster than the next best, hyper Start-up, process start to first answer: simoom's default build (HTTP/1.1, HTTP/2, WebSocket); ahead of 20 of 20Health checks and status endpoints
A small GET answered from memory: load-balancer probes, status pages, the busiest route of most APIs.
JSON APIs
A 1 KB JSON body in, a 1 KB JSON body out, the shape of most service calls.
HTTPS APIs and new TLS clients
The same API over TLS 1.3, and how many new and returning clients the handshake can take per second.
Clients that connect for every request
Serverless callers, scripts and devices that open a connection, send one request and close it.
Service-to-service HTTP/2
64 connections with 100 streams each, as gRPC and service meshes use HTTP/2.
Mobile clients over HTTP/3
QUIC instead of TCP, for clients on lossy or changing networks.
Downloads
64 KB responses; 1 MB responses fill the network card for every server.
Many idle connections
Devices and push clients that stay connected and mostly say nothing.
Traffic spikes
195,000 requests per second offered, more than the network card can carry.
Slow attackers
Real requests while 10,000 slowloris and 1,000 slow-read connections press.
Start-up, size and memory
What a server costs before and while it answers.
Every server, every measure
simoom's advantage on the same droplet, median of rounds: above 1.00 simoom is better, below 1.00 the other server is. Column names link to the charts above.
| server | s1-64 | s1-256 | s1-1024 | p99-50k | cpu-50k | s3 | s4-64k | s5 | s7-tls | s7-full | s7-resumed | s8 | h3 | s9 | s9-total | s10 | idle-10k | idle-100k | cold-plain | cold | size-plain | size | base | peak-s1 | peak-s3 | peak-s7 | peak-h3 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| actix-web | 1.29 | 1.29 | 1.84 | 1.06 | 1.30 | 1.56 | 1.00 | 0.95 | – | – | – | 2.10 | – | 0.05 | 0.98 | 4.42 | 20.75 | 19.90 | 1.93 | 1.24 | 3.33 | 1.58 | 1.07 | 2.40 | 3.74 | – | – |
| axum | 1.34 | 1.36 | 1.99 | 1.17 | 1.51 | 1.27 | 1.00 | 1.09 | – | – | – | 1.23 | – | 2.87 | 0.97 | 1.06 | 38.20 | 38.05 | 1.66 | 1.07 | 3.05 | 1.45 | 0.83 | 5.35 | 5.48 | – | – |
| axum + rustls | – | – | – | – | – | – | – | – | 1.30 | 0.81 | 0.92 | – | – | – | – | – | – | – | 2.03 | 1.31 | 7.34 | 3.48 | 1.76 | – | – | 2.27 | – |
| Caddy | 7.26 | 11.56 | 10.59 | 4282.37 | 3.55 | – | 1.00 | 1.30 | 8.72 | 1.82 | 1.92 | 10.73 | 15.51 | 1000000.00 | 4.31 | 0.99 | 49.48 | 69.29 | 37.02 | 27.77 | 67.60 | 32.06 | 25.06 | 23.49 | – | 8.90 | 2.33 |
| Cameleer's old server | 1.22 | 1000000.00 | 1.28 | 1.71 | 1.49 | – | – | 0.92 | 1000000.00 | 5.91 | 2.21 | – | – | 1.68 | 1.00 | 55845.26 | 5.85 | – | 1.93 | 1.45 | 1.78 | 0.84 | 0.62 | 23.41 | – | 5.10 | – |
| Envoy | 3.72 | 5.83 | 4.18 | 5925.58 | 3.24 | – | – | 2.04 | – | – | – | 3.16 | – | 1000000.00 | 2.91 | 7.30 | 30.51 | 32.52 | 80.93 | 60.70 | 141.94 | 67.32 | 34.48 | 25.18 | – | – | – |
| fasthttp (Go) | 0.80 | 1.08 | 1.66 | 1.18 | 1.56 | 1.26 | – | 1.31 | – | – | – | – | – | 0.82 | 0.97 | 1.01 | 29.09 | 30.72 | 3.13 | 1.76 | 7.81 | 3.70 | 3.42 | 4.29 | 4.44 | – | – |
| Go net/http | 2.18 | 3.75 | 5.00 | 8.17 | 2.24 | 5.27 | 1.00 | 1.14 | 5.82 | 1.79 | 1.94 | 4.31 | – | 1000000.00 | 1.94 | 0.56 | 38.09 | 38.41 | 3.86 | 2.16 | 8.41 | 3.99 | 4.34 | 7.39 | 6.89 | 3.79 | – |
| H2O | 1.95 | 3.58 | 1.97 | 4.09 | 1.93 | – | 1.00 | 1.17 | 1.30 | 1.39 | 1.56 | 0.90 | 0.70 | 27.12 | 2.45 | 0.81 | 2.92 | 3.16 | 15.93 | 11.95 | 2.04 | 0.97 | 2.73 | 2.06 | – | 1.20 | 0.56 |
| HAProxy | 1.32 | 1.58 | 1.25 | 1.24 | 1.50 | – | – | 1.11 | 1.68 | 2.58 | 2.48 | 0.99 | – | 0.74 | 1.00 | 0.66 | 2.93 | 2.46 | 222.69 | 167.02 | 5.12 | 2.43 | 77.49 | 48.73 | – | 20.88 | – |
| hyper | 1.53 | 1.24 | 1.50 | 1.08 | 1.35 | 1.19 | 1.00 | 1.00 | – | – | – | 1.07 | – | 1.26 | 0.99 | 1.02 | 31.05 | 30.45 | 1.57 | 1.01 | 2.81 | 1.33 | 0.74 | 5.79 | 5.95 | – | – |
| Kestrel (.NET) | 1.81 | 2.79 | 3.11 | 4.24 | 2.71 | 4.86 | – | 1.42 | – | – | – | 1.87 | – | 1000000.00 | 0.99 | 201.99 | 18.53 | 19.14 | 385.85 | 241.16 | – | – | 37.75 | 41.71 | 39.70 | – | – |
| may-minihttp | 0.87 | 0.94 | 0.86 | 1.13 | 1.17 | 0.95 | – | 0.96 | – | – | – | – | – | 1.30 | 1.00 | 1.89 | 35.29 | 39.54 | 8.92 | 6.69 | 0.70 | 0.33 | 4.96 | 9.62 | 9.55 | – | – |
| Netty (Java) | 0.83 | 1.06 | 1.76 | 1.31 | 1.41 | 1.23 | – | 1.35 | – | – | – | – | – | 0.81 | 0.98 | 0.80 | 12.64 | 8.66 | 491.59 | 307.24 | – | – | 39.77 | 148.78 | 155.39 | – | – |
| nginx | 1.26 | 2.54 | 1.19 | 2.36 | 1.35 | – | 1.00 | 0.98 | 2.53 | 2.43 | 2.35 | 1.74 | – | 0.21 | 1.00 | 2.02 | 0.94 | 0.99 | 21.74 | 16.31 | 1.75 | 0.83 | 39.28 | 24.26 | – | 10.91 | – |
| ntex | 1.30 | 1.27 | 2.02 | 1.08 | 1.33 | 1.15 | – | 1.06 | – | – | – | – | – | 0.78 | 1.00 | 17.24 | 32.59 | – | 2.20 | 1.42 | 2.49 | 1.18 | 1.17 | 1.86 | 2.97 | – | – |
| quinn + h3 | – | – | – | – | – | – | – | – | – | – | – | – | 1.65 | – | – | – | – | – | 2.09 | 1.34 | 7.84 | 3.72 | 1.96 | – | – | – | 1.30 |
| uWebSockets.js | 0.89 | 1.56 | 1.50 | 1.21 | 1.40 | 1.91 | – | 1.09 | – | – | – | – | – | 0.69 | 0.94 | 2.74 | 1.82 | – | 116.06 | 65.08 | – | – | 43.50 | 31.32 | 40.79 | – | – |
| Vert.x (Java) | 0.66 | 1.03 | 1.68 | 1.02 | 1.24 | 1.34 | – | 1.26 | – | – | – | 1.49 | – | 0.70 | 0.94 | 0.73 | 17.14 | 12.88 | 761.65 | 476.03 | – | – | 51.67 | 150.27 | 153.41 | – | – |
| xitca-web | 1.68 | 1.50 | 2.34 | 1.05 | 1.35 | – | – | 0.77 | – | – | – | – | – | 0.31 | 0.97 | 6.83 | 12.94 | – | 3.50 | 2.25 | 1.39 | 0.66 | 0.76 | 1.49 | – | – | – |
The data behind this section: c4.json, generated from the raw records in bench/results by bench/cloud/c4-report.py and scripts/c4-site.py.
Where simoom is behind
Every measure where another server beat simoom by more than 3% on the same droplet, generated from the same data as the charts.
- Status endpoint, 64 clients: requests/s with 99% within 1 ms. Vert.x (Java) (50% more than simoom), fasthttp (Go) (25% more than simoom), Netty (Java) (20% more than simoom), may-minihttp (15% more than simoom), uWebSockets.js (13% more than simoom). Chart
- Status endpoint, 256 clients: requests/s with 99% within 1 ms. may-minihttp (6% more than simoom). Chart
- Status endpoint, 1,024 clients: requests/s with 99% within 1 ms. may-minihttp (16% more than simoom). Chart
- JSON API, 1 KB in and out, 256 clients: requests/s with 99% within 1 ms. may-minihttp (5% more than simoom). Chart
- A new connection per request, 192 clients: requests/s with 99% within 5 ms. xitca-web (29% more than simoom), Cameleer's old server (9% more than simoom), actix-web (5% more than simoom), may-minihttp (4% more than simoom). Chart
- New TLS 1.3 clients: full handshakes per second. axum + rustls (24% more than simoom). Chart
- Returning TLS 1.3 clients: resumed handshakes per second. axum + rustls (9% more than simoom). Chart
- Service-to-service HTTP/2, 64 connections x 100 streams: requests/s with 99% within 5 ms. H2O (11% more than simoom). Chart
- HTTP/3, 64 clients: requests/s with 99% within 1 ms. H2O (43% more than simoom). Chart
- Traffic spike at 195,000 requests/s offered: answers within 1 ms per second. actix-web (22x more than simoom), nginx (4.7x more than simoom), xitca-web (3.2x more than simoom), uWebSockets.js (45% more than simoom), Vert.x (Java) (43% more than simoom), HAProxy (35% more than simoom), ntex (28% more than simoom), Netty (Java) (23% more than simoom), fasthttp (Go) (22% more than simoom). Chart
- Traffic spike: all answers per second. uWebSockets.js (6% more than simoom), Vert.x (Java) (6% more than simoom), fasthttp (Go) (3% more than simoom), axum (3% more than simoom). Chart
- Under 11,000 slow attackers: p99 of real requests. Go net/http (44% lower than simoom), HAProxy (34% lower than simoom), Vert.x (Java) (27% lower than simoom), Netty (Java) (20% lower than simoom), H2O (19% lower than simoom). Chart
- 10,000 idle connections: memory per connection. nginx (6% less than simoom). Chart
- Program size, stripped: simoom's default build (HTTP/1.1, HTTP/2, WebSocket). may-minihttp (30% smaller than simoom). Chart
- Program size, stripped: simoom's full server (also TLS 1.3 and HTTP/3). may-minihttp (3.0x smaller than simoom), xitca-web (34% smaller than simoom), nginx (17% smaller than simoom), Cameleer's old server (16% smaller than simoom), H2O (3% smaller than simoom). Chart
- Memory at rest (PSS). Cameleer's old server (38% less than simoom), hyper (26% less than simoom), xitca-web (24% less than simoom), axum (17% less than simoom). Chart
- Peak memory while serving HTTP/3 (PSS). H2O (44% less than simoom). Chart
- Coverage. Every figure comes from 4-vCPU droplets with a single-queue network card. Larger machines and multi-queue network cards have not been measured.
How it was measured
Machines and fairness
- Server: DigitalOcean
c-4droplets, 4 dedicated vCPUs, Bangalore region, Ubuntu 24.04, a network card with one receive queue. - Three lanes: each with its own server droplet and two load droplets. simoom ran in every lane and every round, so every server is compared with simoom on the same droplet, with the same load machines, in the same round.
- Rotation: the server droplets rotate between rounds, so each lane meets each droplet. The published ratio is the median of the per-round ratios.
- Open loop: requests are sent at a fixed rate whatever the server does, so a slow server can't slow the load down and hide its own latency.
What is counted
- Throughput: the highest steady rate at which 99% of answers arrive within 1 ms (5 ms for new connections, downloads and HTTP/2) with no errors. A run that stalls counts as a miss.
- Rounds: round 1 ran every scenario for every server. Rounds 2 and 3 repeated the status endpoint at 256 clients, the JSON API, new connections, TLS and CPU on the other two droplets. Each chart says how many rounds it holds.
- Builds: each server in its fastest documented configuration; the programs and their configuration are in bench/competitors.
- simoom: the benchmark server with all features, commit
a81c368. Its smallest build appears only in the footprint charts.
The review that led to this campaign: docs/benchmark-review.md. The analysis, with every anomaly: campaign 4 analysis. Raw records, scripts and programs: bench/results, bench/cloud.
Against the server it replaced
The Cameleering test that matters most: the original. simoom replaces Cameleer's thread-per-connection server (cameleer-http). Both return the same 13-byte answer on the same machine (WSL2).
Start-up and idle memory (2026-11-11)
| build | to first answer | idle memory |
|---|---|---|
| simoom, plain | 0.73 ms | 1,018 KB |
| cameleer-http, plain | 0.77 ms | 1,017 KB |
| simoom, TLS (P-256) | 0.87 ms | 1,360 KB |
| cameleer-http, TLS | 1.37 ms | 1,317 KB |
10 alternating rounds; TLS memory after the fix of 2026-11-12 (issue K11).
Under load (2026-11-09)
| measure | simoom | cameleer-http |
|---|---|---|
| requests per second | 293k–311k | 172k–173k |
| p99 latency | 0.32–0.44 ms | 0.87–0.91 ms |
| CPU per request | about 13 µs | about 23 µs |
| 1,000 idle connections | 2.7 MB | 7.7 MB |
Server on 4 CPUs, 64 connections, closed-loop load from 8 other CPUs.
The owner's requirement was start-up and memory within 5% of cameleer-http. Idle memory with TLS is 3.3% higher; everything else is level or better. This result is the simoom row of the Cameleering ledger.
What a build adds to your binary
Bytes added to examples/hello.rs over an empty fn main, stripped, x86-64 Linux, dist profile. The budgets are targets the build enforces: scripts/size.sh fails when one is exceeded.
| build | size | budget |
|---|---|---|
| HTTP/1.1 only | 214,568 B | 256,000 B |
| HTTP/1.1, HTTP/2, TLS, io_uring | 583,680 B | 614,400 B |
| everything: HTTP/1.1, HTTP/2, HTTP/3, TLS, WebSocket, io_uring | 935,064 B | 1,048,576 B |
The HTTP/1.1 and full rows are from 2026-11-11, the TLS row from 2026-11-12.
Whole benchmark programs, simoom against every other server, are in the footprint charts above: start-up, size and memory.
Conformance and interop
| check | result |
|---|---|
| h2spec 2.6.0 | 146/146, in 30 consecutive runs |
| QUIC Interop Runner, server role, against ngtcp2, quiche and quic-go | 54 of 58 supported pairs; the 4 failures are 0-RTT (refused by design) and ECN (not implemented) |
| HTTP Garden, next to nginx, Apache httpd, h2o, hyper, gunicorn and Go | 0 desyncs, 0 dangerous discrepancies |
| Request smuggling behind nginx 1.24 and haproxy 2.8 | 165 streams, 0 desyncs; accepted 0 requests that both refused |
| testssl.sh 3.2.1 | no vulnerabilities found |
| Test suite | 777 tests on Windows, 791 on Linux, zero warnings |
Versions, commands and details: Security. No independent security audit has been done yet.
Common questions
What is the fastest Rust HTTP server?
It depends on the use case. In campaign 4, with 10 Rust servers among the 21 on the same droplets, may-minihttp led plain requests per second by 5–16% and simoom was second; simoom led HTTPS throughput, CPU per request and start-up; actix-web kept the most answers within 1 ms during a traffic spike. Numbers from different machines should not be compared: droplets of the same type differed by up to 7x.
Why p99 under 1 ms instead of maximum requests per second?
A server that answers more requests but makes some of them wait seconds is not faster for the people waiting. The headline figure is the highest steady rate at which 99% of answers arrive within 1 ms, with the load sent at a fixed rate so a slow server cannot slow the load down and hide its latency.
Why are only servers on the same droplet compared?
Droplets of the same type differed by up to 7x for every server in earlier campaigns. A comparison across droplets would measure the machines, not the servers. In campaign 4 simoom ran in every lane and every round, so every server has a simoom run on its own droplet to be compared with.
Can I rerun the benchmarks?
Yes. The scripts are in bench/cloud in the repository, the competitor programs in bench/competitors, and the raw records, HDR logs and analyses in bench/results. bench/cloud/c4-report.py turns the records into the tables on this page, and scripts/size.sh reproduces the size table.
Has anyone else measured simoom?
Not yet. Every figure here was measured by the project. If you measure it differently and get a different number, open an issue with your method.