PlaintextGET /plaintext answers 13 bytes over kept-alive connections: the cost of HTTP itself.
fourneau-zig102,004
roux84,530
axum39,894
go22,501
basic-webserver14,383
table
competitor
req/s (median)
p95 ms
p99 ms
p99.9 ms
rounds
spread %
server CPU %
loader CPU %
Mbit/s in / out
limited by
steal %
peak RSS
fourneau-zig
102,004
3.75
4.27
5.49
102,004 · 99,397 · 110,100
10.5
100.0
50.4
125 / 160
server CPU
0.1
112.7 MiB
roux
84,530
4.54
5.39
6.32
85,018 · 76,793 · 84,530
9.7
99.2
39.9
104 / 133
server CPU
0.1
110.2 MiB
axum
39,894
7.94
8.53
10.30
42,597 · 39,894 · 39,612
7.5
100.0
29.2
49 / 63
server CPU
0.1
14.9 MiB
go
22,501
18.22
22.03
28.03
22,501 · 22,273 · 23,457
5.3
100.0
16.4
28 / 35
server CPU
0.2
22.6 MiB
basic-webserver
14,383
23.26
25.65
28.65
14,396 · 14,383 · 12,680
11.9
100.0
11.1
18 / 23
server CPU
0.0
25.7 MiB
Echo 4 KiBPOST /echo with a 4 KiB body, answered with the same bytes: reading bodies and writing larger responses.
fourneau-zig33,359
roux32,007
axum21,698
go12,344
basic-webserver9,525
table
competitor
req/s (median)
p95 ms
p99 ms
p99.9 ms
rounds
spread %
server CPU %
loader CPU %
Mbit/s in / out
limited by
steal %
peak RSS
fourneau-zig
33,359
10.06
12.00
17.52
35,664 · 33,336 · 33,359
7.0
100.0
29.1
1,237 / 1,179
server CPU, network
0.4
112.7 MiB
roux
32,007
10.34
11.81
18.58
33,985 · 28,080 · 32,007
18.5
100.0
26.0
1,194 / 1,128
server CPU
0.2
110.2 MiB
axum
21,698
14.53
16.37
19.32
23,404 · 21,688 · 21,698
7.9
99.7
27.5
836 / 767
server CPU
0.2
14.9 MiB
go
12,344
32.50
40.19
46.32
12,427 · 12,235 · 12,344
1.6
100.0
19.9
488 / 443
server CPU
0.1
22.6 MiB
basic-webserver
9,525
33.49
36.31
41.54
11,048 · 9,525 · 9,333
18.0
100.0
13.5
343 / 336
server CPU
0.2
30.7 MiB
TemplatesGET /menu renders a 12-row HTML table from a template per request, every value escaped: the work of a server-rendered page.
fourneau-zig67,616
roux50,193
axum37,370
go10,148
basic-webserver4,505
table
competitor
req/s (median)
p95 ms
p99 ms
p99.9 ms
rounds
spread %
server CPU %
loader CPU %
Mbit/s in / out
limited by
steal %
peak RSS
fourneau-zig
67,616
5.12
5.88
8.52
73,961 · 58,017 · 67,616
23.6
99.6
35.0
80 / 500
server CPU
0.2
112.7 MiB
roux
50,193
7.12
8.07
12.36
55,276 · 50,193 · 45,089
20.3
100.0
25.7
59 / 372
server CPU
0.1
110.2 MiB
axum
37,370
8.82
9.84
11.48
37,370 · 38,150 · 35,298
7.6
100.0
26.2
44 / 279
server CPU
0.1
14.9 MiB
go
10,148
42.24
48.72
55.29
9,676 · 10,599 · 10,148
9.1
100.0
7.8
12 / 76
server CPU
0.1
22.6 MiB
basic-webserver
4,505
69.97
75.13
83.01
5,001 · 4,505 · 4,421
12.9
100.0
4.9
5 / 36
server CPU
0.1
30.7 MiB
SSE (Datastar)GET /sse with Datastar's signals in the query, answered with a stream of ten Datastar events, a chunk each: the work of a Datastar action.
fourneau-zig63,961
roux28,347
axum27,929
go8,354
basic-webserver1,897
table
competitor
req/s (median)
p95 ms
p99 ms
p99.9 ms
rounds
spread %
server CPU %
loader CPU %
Mbit/s in / out
limited by
steal %
peak RSS
fourneau-zig
63,961
5.73
6.45
8.17
71,183 · 57,679 · 63,961
21.1
100.0
45.6
92 / 645
server CPU
0.1
112.7 MiB
roux
28,347
11.77
13.06
14.92
28,347 · 29,040 · 27,663
4.9
100.0
21.7
41 / 286
server CPU
0.2
110.2 MiB
axum
27,929
10.89
12.10
13.33
30,096 · 27,929 · 27,778
8.3
100.0
31.2
40 / 282
server CPU
0.1
14.6 MiB
go
8,354
48.61
56.97
69.08
8,052 · 8,354 · 8,903
10.2
100.0
17.4
20 / 106
server CPU
0.1
22.1 MiB
basic-webserver
1,897
170.21
193.36
227.09
2,159 · 1,890 · 1,897
14.2
100.0
10.3
8 / 30
server CPU
0.3
30.9 MiB
Connection churnGET /plaintext on a new connection every request: accepting, and closing, as fast as possible.
fourneau-zig16,113
roux15,573
axum9,704
go7,754
basic-webserver5,004
table
competitor
req/s (median)
p95 ms
p99 ms
p99.9 ms
rounds
spread %
server CPU %
loader CPU %
Mbit/s in / out
limited by
steal %
peak RSS
fourneau-zig
16,113
6.15
8.28
10.69
16,113 · 15,089 · 16,273
7.4
88.5
41.7
63 / 62
connections (nothing saturated)
0.2
112.7 MiB
roux
15,573
6.01
7.37
10.55
15,666 · 15,573 · 15,458
1.3
92.9
40.6
61 / 60
server CPU
0.1
110.2 MiB
axum
9,704
10.30
12.03
14.47
10,744 · 9,401 · 9,704
13.8
95.1
27.6
36 / 38
server CPU
0.1
14.9 MiB
go
7,754
11.48
13.05
16.50
7,654 · 7,754 · 8,592
12.1
98.0
22.4
30 / 30
server CPU
0.2
22.6 MiB
basic-webserver
5,004
17.62
20.90
25.08
5,263 · 4,880 · 5,004
7.7
100.0
14.8
19 / 20
server CPU
0.1
29.0 MiB
Under load: Templatesp99 latency against the offered rate (open loop: requests arrive at a fixed rate whatever the server does). Each server is offered 50% to 120% of its own maximum above.
offered requests per second →
axum
roux
basic-webserver
go
fourneau-zig
the loader was the limit
Under load: RealWorld (Conduit)The mean latency of every request against the offered rate: the article list (50%), an article (30%), a comment (15%) and a favorite (5%) at once, open loop, at the same rates for every server, each climbing until it falls behind.
offered requests per second →
go
fourneau-zig
basic-webserver
axum
roux
the loader was the limit
How it runs
A race runs at 03:00 New York time when fourneau, roux or this repository has a new commit. Each result names the commits it raced.
Each server class gets fresh DigitalOcean droplets: the server on one, the load generator (oha) on a bigger one, over the private network.
Five workloads raced flat out: plaintext, a 4 KiB echo, a templated HTML page, a Datastar event stream, and a new connection per request. Three rounds in random order; the median counts, of throughput and of each latency percentile.
And one with a database: a slice of RealWorld’s Conduit API on SQLite, reads and writes at once, offered at the same rising rates to every server.