Epeaky benchmarks: one encrypted room of 200 and 440 devices
On Hetzner's smallest arm server (CAX11: 2 cores, 4 GB), one Epeaky room of 200 devices took 20 messages a second with every message reaching every device, p95 49 ms from send to arrival, at a peak of about 1.2 of the 2 cores and 190 MB of memory. On 2 shared x86 vCPUs with 4 GB (Hetzner CPX22), a room of 440 devices took 50 messages a second, all 397,600 deliveries, p95 50 ms. That server tops out near 32,000 deliveries a second.
200 devices, 2 arm cores
20 devices wrote and 180 only listened, all in one room. Each rate was held for 20 seconds.
| Messages a second | Sent | Delivered to listeners | Deliveries a second | p50 | p95 | p99 |
|---|---|---|---|---|---|---|
| 5 | 100 | 18,000 of 18,000 | 900 | 39 ms | 50 ms | 99 ms |
| 10 | 200 | 36,000 of 36,000 | 1,800 | 39 ms | 47 ms | 66 ms |
| 20 | 393 | 70,740 of 70,740 | 3,537 | 39 ms | 49 ms | 78 ms |
| 50 | 908 (81 refused) | 178,020 | 8,901 | 40 ms | 50 ms | 73 ms |
| 100 | 1,027 (917 refused) | 350,460 | 17,523 | 134 ms | 343 ms | 641 ms |
Joining took 10.9 seconds for the 20 writing devices (each a full member with its own MLS state) and 22.7 seconds for the 180 listeners.
440 devices, 2 shared x86 vCPUs
40 devices wrote and 400 listened, in one room.
| Messages a second | Sent | Delivered to listeners | Deliveries a second | p50 | p95 | p99 |
|---|---|---|---|---|---|---|
| 25 | 477 | 190,800 of 190,800 | 9,540 | 45 ms | 53 ms | 89 ms |
| 50 | 994 | 397,600 of 397,600 | 19,880 | 43 ms | 50 ms | 65 ms |
| 100 | 1,522 | 616,400 | 30,820 | 385 ms | 638 ms | 949 ms |
| 150 | 1,184 | 641,182 | 32,059 | 373 ms | 590 ms | 1,046 ms |
The cost of encryption in big rooms
Every membership change in an MLS room is a commit that each device applies and the den checks. In a room of 1,000 members, a device applied one in 18 ms and the den checked one in 20 ms. A room's GroupInfo is about 190 KB at that size.
How it was measured
- The clients are Epeaky's own page code (
den.jsand the MLS WebAssembly), run in Node on one laptop. The writers are full members that open every message; the listeners are devices that enter and receive, spread over four processes so the laptop's own work is not what is measured. - Latency runs from the moment a writer sends to the moment a listener receives, on the same laptop's clock, so it includes two trips across the internet to the server in Germany and back.
- Messages were about 100 characters of text. A delivery is one encrypted message reaching one device.
- The servers ran the standard install (the den behind Caddy, in Docker) on Ubuntu 24.04.
What this does not measure
- Voice, files or images.
- Phones on mobile networks, or a real group's mix of quiet and busy rooms.
- Many rooms at once. Every device here was in the same room, which is the hardest case for one room and the easiest for the rest of the server.
Repeat it
On the server, make one invite per test device and keep their codes, one a line (epeaky invite 200 1 | grep -o '[0-9a-f]\{64\}' > invites.txt), and allow that many door requests from one address with DEN_DOOR_PER_MINUTE. Then, from a checkout:
cd web && ./build.sh dist && node tests/load.mjs https://den.example.org invites.txt 20 180 5 10 20 50 100The arguments are writers, listeners and the rates to try. tests/bench.mjs measures the MLS costs by room size. Both are in web/tests. If your numbers differ, tell us.