# Scale API Maker WebSockets to N users : one big server or several small ones

> How API Maker serves N WebSocket users : servers behind a load balancer which share one Redis, the rule to count them, and one big server against several small ones, measured.

Source: https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html

<nav class="am-bench-switch" aria-label="WebSocket benchmark servers">
Shared CPU

- [1 vCPU1 GB · 26k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-1-vcpu-1gb.html)
- [2 vCPU4 GB · 338k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-2-vcpu-4gb.html)
- [4 vCPU8 GB · 802k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-4-vcpu-8gb.html)
- [8 vCPU32 GB · 3.66M clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-shared-8-vcpu-32gb.html)

Dedicated CPU

- [2 vCPU4 GB · 338k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-2-vcpu-4gb.html)
- [4 vCPU8 GB · 796k clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-4-vcpu-8gb.html)
- [8 vCPU16 GB · 1.73M clients](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/linode-dedicated-8-vcpu-16gb.html)

Compare

- [WebSocketsthe answers](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/index.html)
- [All resultsevery server side by side](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html)
- [Scale to N usersone server or many](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html)

</nav>

WebSocket benchmarks · Scaling · API Maker 4.0.0 · 14 October 2026

**Scale WebSockets to N users : add servers, they share one Redis.**

A WebSocket stays on the server it reached, and a notification can come from any server : Redis carries it to the one which holds the client. So N users are a matter of memory, spread over as many servers as it takes. Measured on 3 clusters of the same price : the same 8 dedicated vCPUs and 16 GB for API Maker as one server, two, and four, with MongoDB and Redis on a server of their own.

Clients on 1 server

2,022,026

1 × 8 vCPU · 16 GB, one Redis

Memory per client

8.5 to 8.8KB

the whole of it : API Maker, the kernel, Redis

Servers for N users

N ÷ C + 1

C : the clients one server holds, by its memory

One server of four stops

25 %

of the clients dropped, back after 38.0 s

## The picture

> Diagram : N WebSocket users : a load balancer, API Maker servers which each hold their clients, one Redis they share
>
> How API Maker serves N WebSocket users : the clients keep a WebSocket open to a load balancer, which passes each one to an API Maker server ; every server holds the clients which reached it, about 8 to 9 KB each ; all the servers share one Redis, which keeps a key and a channel per subscription and carries every notification to the server which holds the client, and one MongoDB. More users : more servers.

- **The clients** connect to one address, `wss://ws.example.com`, with their tokens in the query string.
- **A load balancer** ends TLS and hands each WebSocket to one API Maker server : Caddy (the installer writes its line), HAProxy, or the load balancer of your cloud. It needs no sticky session, a WebSocket stays on the server it reached.
- **Each API Maker server** checks the tokens, keeps its clients and their subscriptions, and pings them. Its clients cost it memory, about 8.5 to 8.8 KB each, and almost no CPU while they wait.
- **One Redis**, the internal Redis of API Maker, is shared by the servers : a key and a channel for every subscription. The server which answers an API call, or runs `emitEventWS`, publishes the notification there ; the server which holds the client hears it and sends it.
- **MongoDB** keeps the accounts, the events and their can user connect code : read when a client subscribes, then kept by each server.

## Count the servers

1. **Memory.** Users connected at once × the memory of a client (8.5 to 8.8 KB with both tokens and one subscription ; more subscriptions cost a little more each). It is spread over the API servers ; Redis takes 1.0 to 1.1 KB of it per subscription.
2. **Servers.** That memory ÷ what one server has left once API Maker, its sandboxes and Linux have theirs : the [page of each server](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html#capacity) gives the clients it held. Add one server, so that the others can take the clients of one which stops.
3. **The rest follows.** New clients a second and notifications a second grow with the vCPUs : the [results](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/summary.html#connect) of each server size say how many.

| Users connected at once | Memory they take, in all | Servers of 16 GB (1,732,035 clients each) | Memory of Redis |
|--:|--:|--:|--:|
| **10,000** | 86 MB | 1 + 1 spare | 10 MB |
| **100,000** | 861 MB | 1 + 1 spare | 104 MB |
| **500,000** | 4.2 GB | 1 + 1 spare | 522 MB |
| **1,000,000** | 8.4 GB | 1 + 1 spare | 1 GB |
| **5,000,000** | 42.1 GB | 3 + 1 spare | 5.1 GB |

The open files of the service and the table of the firewall follow the memory of the server (the installer, 256 for each MB) : the memory is what ends, on every server measured.

## One big server or several small ones

The same 8 dedicated vCPUs and 16 GB of memory for API Maker, at the same price a month, as **one** server, **two**, and **four**. Each time, MongoDB and Redis run on a server of their own, the clients go to the API servers in turn, and autocannon calls every API server at once.

**Clients connected at once, for the same price**

[1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) · $144 / month · 2,022,026

[2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) · $144 / month · 1,915,960

[4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) · $144 / month · 1,619,372

**New clients per second : both tokens and a subscription**

[1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) · $144 / month · 12,412

[2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) · $144 / month · 12,696

[4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) · $144 / month · 10,297

| | [1 × 8 vCPU · 16 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-1x8) | [2 × 4 vCPU · 8 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-2x4) | [4 × 2 vCPU · 4 GB](https://docs.apimaker.dev/v4/docs/benchmarks/websockets/scaling.html#cluster-4x2) |
|---|--:|--:|--:|
| Clients connected at once | **2,022,026** | **1,915,960** | **1,619,372** |
| … on each server | 2,022,026 | 957,980 | 404,843 |
| Memory per client, in all | 8.8 KB | 8.8 KB | 8.6 KB |
| New clients a second (both tokens, a subscription) | **12,412** | **12,696** | **10,297** |
| … connect only, both tokens | 19,917 | 21,417 | 17,882 |
| A notification for one person : delivery p50 | 1.01 ms | 1.18 ms | 1.37 ms |
| … p99 | 1.72 ms | 1.80 ms | 2.51 ms |
| Notifications a second, one person each | 24,305 | 24,977 | 25,566 |
| Notifications a second, broadcast | 217,711 | 228,910 | 272,609 |
| One server stops : clients dropped | 1,516,519 of 1,516,519 (100 %) | 383,192 of 766,384 (50 %) | 242,906 of 971,623 (25 %) |
| … all back after | 221 s | 68.0 s | 38.0 s |

- **They hold about the same.** Every server keeps some memory for itself (API Maker at rest, two sandboxes, Linux, Docker), so four small servers hold a little less than one big one.
- **They let in about as many clients a second**, and tell as many : the work is the same, spread over the same vCPUs, and Redis does its part on its own server.
- **A server which stops takes its share of the clients with it** : all of them on one big server, a quarter on four. The clients come back by themselves, in 68.0 s on 2 × 4 vCPU · 8 GB and 38.0 s on 4 × 2 vCPU · 4 GB ; on one server they wait for it to start again, 221 s in all.
- **Several servers can be restarted one at a time** : a new version of API Maker, or of your code, without every client going away at once.

**So : one server while everything fits on it, several as soon as the clients must not all drop together.** Keep the other servers under 75 % full with four of them (50 % with two) : they then have room for the clients of the one which stops.

## What ends first

| Limit | Where | What it is |
|---|---|---|
| **Memory** | Each API server | 8.5 to 8.8 KB per client. The first limit on every server measured. |
| Open files | Each API server | A client is one open file. The installer lets the service open as many as the firewall tracks connections, 256 for each MB of memory and 1,048,576 at the least (`LimitNOFILE`, and `fs.nr_open` with it) : API Maker keeps a few for itself, and a sixteenth of its connections (4,096 at the most) for the calls of the APIs : without them, a server whose clients held every connection would answer no API call for as long as they stay. One more client is answered `503`. |
| Tracked connections | Each API server | Docker makes Linux track every connection, and Linux drops new ones once its table is full (`nf_conntrack: table full`). As Linux sets it up, the table holds 262,144 connections on 4 GB or more, and a closed connection stays in it two minutes : the installer gives it room for 256 connections per MB of memory (twice the clients the memory holds, for the ones which come back after a restart while their old connections are still in it), and API Maker says at its start when the table is what limits it. |
| Memory of the network | Each API server | A socket which holds something unread, or something its client has not acknowledged yet, keeps a page of the memory Linux gives all its TCP connections together (`net.ipv4.tcp_mem` : about 9 % of the memory of the server, as Linux sets it up). Past it, Linux slows every connection of the server down, the ones to its databases too : it happens when every client of a full server does something in the same second (they all come back, they all leave, they are all told). API Maker raises that memory as its clients come, two pages for each connection and never more than a quarter of the memory of the server (`tcpMemoryPercent`), and closes a socket without waiting for anything else : 601,479 clients which left in the same second were closed after 18.0 s. |
| Ports of a proxy | The load balancer | A proxy reaches one port of one server from one address about 64,000 times (28,000 as Linux sets it up). More clients per server behind a proxy need more addresses on the proxy, or a load balancer which passes the connections on without opening its own. |
| Redis | The data server | One key and one channel per subscription, in memory ; one thread carries every notification. With 2,022,026 clients it held 2,010 MB. |
| Tokens | Your application | A client is closed when its token runs out : give tokens different lifetimes, or the clients all come back in the same second. |

## The clusters, one by one

### 1 × 8 vCPU · 16 GB

| | |
|---|---|
| API servers | 1 × Dedicated 16 GB (g6-dedicated-8) : 8 dedicated vCPUs and 16 GB each, $144 a month in all. API Maker and its two sandboxes on each, attached to the data server by the installer (`--secondary`) |
| Data server | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM). MongoDB 8.0.10 and Redis 7.0.5 of API Maker, in Docker ; its own API Maker stopped |
| CPU | AMD EPYC 7642 48-Core Processor |
| System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 |
| API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy |
| Network limits | as the installer sets them, on every API server : 4,093,696 connections tracked (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted, 4,093,696 open files. The memory of all its TCP connections together : raised by API Maker as the clients came, to 3.9 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) |
| Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7642 48-Core Processor, 16 dedicated vCPUs. The clients go to the API servers in turn, as a load balancer hands them out ; autocannon calls every API server at the same time |
| Network | A VLAN of the same data centre, round trip 0.33 ms (ping) |
| Date | 14 October 2026, 03:19 to 04:02 UTC |

Clients connected

2,022,026

2,022,026 on each of 1 server

Memory per client

8.8KB

API Maker 3.2 · kernel 4.5 · Redis 1.1

New clients / second

12,412

both tokens and a subscription · 19,917 without one

Notification delivered in

1.01ms

p50 at 1,000 a second · p99 1.72 ms

The run stopped adding clients at **2,022,026** : the memory of the server `api-1` was full. 2,116 MB of its 15,992 MB were still counted as available, and Linux had moved 1,317 MB to the swap since the clients began to connect, to make that room : 799 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server).

> Diagram : Clients connected and memory used during the run
>
> The run of this server, second after second : the WebSocket clients connected, up to 2,022,026, and the memory the server used, up to 14,465 MB of 15,991 MB.

| Clients connected | API Maker, all servers | Linux kernel, all servers | API servers, used | Least available on a server | Redis (its data) | Data server, used | CPU busy |
|---|--:|--:|--:|--:|--:|--:|--:|
| No client (at rest) | 127 MB | 184 MB | 792 MB | 15,200 MB | 1 MB | 713 MB | 0.3 % |
| **10,000** clients | 166 MB | 328 MB | 1,816 MB | 14,176 MB | 12 MB | 704 MB | 1.8 % |
| **100,000** clients | 451 MB | 634 MB | 2,359 MB | 13,632 MB | 103 MB | 896 MB | 0.9 % |
| **200,000** clients | 764 MB | 1,080 MB | 3,029 MB | 12,963 MB | 204 MB | 1,009 MB | 1.9 % |
| **400,000** clients | 1,408 MB | 1,971 MB | 4,428 MB | 11,564 MB | 404 MB | 1,204 MB | 3.8 % |
| **600,000** clients | 2,062 MB | 2,856 MB | 5,810 MB | 10,182 MB | 625 MB | 1,448 MB | 5.7 % |
| **800,000** clients | 2,666 MB | 3,745 MB | 7,166 MB | 8,826 MB | 810 MB | 1,620 MB | 7.8 % |
| **1,000,000** clients | 3,344 MB | 4,634 MB | 8,561 MB | 7,431 MB | 995 MB | 1,812 MB | 9.8 % |
| **1,200,000** clients | 3,954 MB | 5,524 MB | 9,903 MB | 6,089 MB | 1,249 MB | 2,064 MB | 12.1 % |
| **1,400,000** clients | 4,562 MB | 6,412 MB | 11,349 MB | 4,643 MB | 1,430 MB | 2,265 MB | 14.5 % |
| **1,600,000** clients | 5,167 MB | 7,293 MB | 12,658 MB | 3,334 MB | 1,619 MB | 2,479 MB | 16.7 % |
| **1,800,000** clients | 5,713 MB | 8,136 MB | 13,907 MB | 2,085 MB | 1,800 MB | 2,649 MB | 19.5 % |
| **2,000,000** clients | 5,972 MB | 9,014 MB | 13,747 MB | 2,245 MB | 1,990 MB | 2,842 MB | 22.1 % |
| **2,022,026** clients | 5,890 MB | 9,112 MB | 13,687 MB | 2,305 MB | 2,010 MB | 2,874 MB | 21.7 % |

**New clients**

Clients / second

12,412

745,486 clients in 60 s, 100 at a time

Let in after, p50

7.04ms

connected 2.10 ms · TCP 0.24 ms

Let in after, p99

10.4ms

max 21.3 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **7.0 vCPU** · Redis **0.5 vCPU** · whole server busy **91 %** · load generator busy **26 %**

    am_ws_load · connect with both tokens and subscribe · 1 server

    ```text
    $ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>" --register 'order-updates'
    Running 60s test @ ws://<server>:38246
    100 clients at a time : connect, CONNECTED, REGISTER, leave

    ┌─────────────┬─────────┬─────────┬──────────┬──────────┬─────────┬─────────┬──────────┐
    │ Stat        │ 2.5%    │ 50%     │ 97.5%    │ 99%      │ Avg     │ Stdev   │ Max      │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ TCP connect │ 0.18 ms │ 0.24 ms │ 0.44 ms  │ 0.57 ms  │ 0.26 ms │ 0.15 ms │ 10.94 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ CONNECTED   │ 0.77 ms │ 2.1 ms  │ 3.98 ms  │ 4.43 ms  │ 2.17 ms │ 0.85 ms │ 12.06 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ REGISTER    │ 4.6 ms  │ 7.04 ms │ 9.69 ms  │ 10.42 ms │ 7.06 ms │ 1.29 ms │ 21.26 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ Left        │ 5.52 ms │ 7.93 ms │ 11.06 ms │ 11.87 ms │ 8.03 ms │ 1.4 ms  │ 23.38 ms │
    └─────────────┴─────────┴─────────┴──────────┴──────────┴─────────┴─────────┴──────────┘
    ┌─────────────┬────────┬────────┬────────┬────────┬──────────┬────────┬────────┐
    │ Stat        │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg      │ Stdev  │ Min    │
    ├─────────────┼────────┼────────┼────────┼────────┼──────────┼────────┼────────┤
    │ Clients/Sec │ 11,238 │ 11,547 │ 12,468 │ 12,797 │ 12,424.8 │ 301.49 │ 11,238 │
    └─────────────┴────────┴────────┴────────┴────────┴──────────┴────────┴────────┘

    Time from the start of the connection to each step. Clients counted once per second.
    # of samples: 60

    745k clients let in in 60.06s, 0 refused or lost
    ```

**One person, 1,000 a second**

Calls / second (paced)

1,000

60,000 calls in 60 s, 10 connections

Notifications / second

983

60,010 received by 10,000 clients

Delivery p50

1.01ms

average 1.04 ms

Delivery p99

1.72ms

max 5.91 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **0.3 vCPU** · Redis **0.0 vCPU** · whole server busy **4 %** · load generator busy **3 %**

    autocannon · A notification for one person, 1,000 a second

    ```text
    $ autocannon -c 10 -d 60 -R 1000 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    10 connections

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬──────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max  │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼──────┤
    │ Latency │ 0 ms │ 1 ms │ 1 ms  │ 1 ms │ 0.87 ms │ 0.41 ms │ 8 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴──────┘
    ┌───────────┬────────┬────────┬────────┬────────┬────────┬───────┬────────┐
    │ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev │ Min    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Req/Sec   │ 999    │ 999    │ 1,000  │ 1,001  │ 1,000  │ 0.32  │ 999    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Bytes/Sec │ 357 kB │ 357 kB │ 357 kB │ 357 kB │ 357 kB │ 81 B  │ 357 kB │
    └───────────┴────────┴────────┴────────┴────────┴────────┴───────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 0            │
    ├────────────┼──────────────┤
    │ 10         │ 0            │
    ├────────────┼──────────────┤
    │ 25         │ 1            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 1            │
    ├────────────┼──────────────┤
    │ 90         │ 1            │
    ├────────────┼──────────────┤
    │ 97.5       │ 1            │
    ├────────────┼──────────────┤
    │ 99         │ 1            │
    ├────────────┼──────────────┤
    │ 99.9       │ 4            │
    ├────────────┼──────────────┤
    │ 99.99      │ 7            │
    ├────────────┼──────────────┤
    │ 99.999     │ 8            │
    └────────────┴──────────────┘

    61k requests in 60.03s, 21.4 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 64.05s

    ┌──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max     │
    ├──────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Delivery │ 0.84 ms │ 1.01 ms │ 1.45 ms │ 1.72 ms │ 1.04 ms │ 0.17 ms │ 5.91 ms │
    └──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
    ┌───────────┬────┬──────┬───────┬───────┬───────┬────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5% │ Avg   │ Stdev  │ Min │
    ├───────────┼────┼──────┼───────┼───────┼───────┼────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 1,000 │ 1,000 │ 951.8 │ 213.87 │ 0   │
    └───────────┴────┴──────┴───────┴───────┴───────┴────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    60k notifications received in 64.05s (60,010 of 60,000 expected), 10.7 MB read
    ```

**One person, as many as the servers take**

Calls / second

24,592

1,475,433 calls in 60 s, 100 connections

Notifications / second

24,305

1,475,533 received by 10,000 clients

Delivery p50

3.88ms

average 3.93 ms

Delivery p99

5.66ms

max 529 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **7.7 vCPU** · Redis **0.3 vCPU** · whole server busy **97 %** · load generator busy **28 %**

    autocannon · A notification for one person, as many as the server takes

    ```text
    $ autocannon -c 100 -d 60 -w 10 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    100 connections
    10 workers

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max    │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤
    │ Latency │ 2 ms │ 4 ms │ 5 ms  │ 5 ms │ 3.54 ms │ 0.81 ms │ 251 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬───────────┬────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg       │ Stdev  │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼────────┼─────────┤
    │ Req/Sec   │ 22,895  │ 22,927  │ 24,831  │ 25,087  │ 24,591.47 │ 622.5  │ 22,887  │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼────────┼─────────┤
    │ Bytes/Sec │ 8.17 MB │ 8.18 MB │ 8.86 MB │ 8.95 MB │ 8.78 MB   │ 222 kB │ 8.17 MB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴───────────┴────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 2            │
    ├────────────┼──────────────┤
    │ 2.5        │ 2            │
    ├────────────┼──────────────┤
    │ 10         │ 3            │
    ├────────────┼──────────────┤
    │ 25         │ 3            │
    ├────────────┼──────────────┤
    │ 50         │ 4            │
    ├────────────┼──────────────┤
    │ 75         │ 4            │
    ├────────────┼──────────────┤
    │ 90         │ 4            │
    ├────────────┼──────────────┤
    │ 97.5       │ 5            │
    ├────────────┼──────────────┤
    │ 99         │ 5            │
    ├────────────┼──────────────┤
    │ 99.9       │ 6            │
    ├────────────┼──────────────┤
    │ 99.99      │ 11           │
    ├────────────┼──────────────┤
    │ 99.999     │ 28           │
    └────────────┴──────────────┘

    1476k requests in 60.01s, 527 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 63.71s

    ┌──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max      │
    ├──────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
    │ Delivery │ 2.63 ms │ 3.88 ms │ 5.31 ms │ 5.66 ms │ 3.93 ms │ 2.62 ms │ 528.9 ms │
    └──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬────────┬────────┬──────────┬─────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%    │ 97.5%  │ Avg      │ Stdev   │ Min │
    ├───────────┼────┼──────┼────────┼────────┼──────────┼─────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 24,801 │ 25,090 │ 23,602.0 │ 4602.67 │ 0   │
    └───────────┴────┴──────┴────────┴────────┴──────────┴─────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    1.48M notifications received in 63.71s (1,475,533 of 1,475,433 expected), 264.2 MB read
    ```

**Broadcast, as many as the servers take**

Calls / second

222

13,321 calls in 60 s, 10 connections

Notifications / second

217,711

13,330,000 received by 1,000 clients

Delivery p50

36.7ms

average 36.7 ms

Delivery p99

56.8ms

max 77.6 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **6.9 vCPU** · Redis **0.3 vCPU** · whole server busy **89 %** · load generator busy **32 %**

    autocannon · A broadcast to 1,000 clients, as many as the server takes

    ```text
    $ autocannon -c 10 -d 60 -w 10 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    10 connections
    10 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
    │ Latency │ 30 ms │ 44 ms │ 59 ms │ 63 ms │ 44.45 ms │ 7.06 ms │ 77 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Req/Sec   │ 206     │ 208     │ 221     │ 234     │ 222.02  │ 9.42    │ 206     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Bytes/Sec │ 74.2 kB │ 74.9 kB │ 79.6 kB │ 84.3 kB │ 79.9 kB │ 3.39 kB │ 74.2 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 11           │
    ├────────────┼──────────────┤
    │ 0.01       │ 12           │
    ├────────────┼──────────────┤
    │ 0.1        │ 21           │
    ├────────────┼──────────────┤
    │ 1          │ 27           │
    ├────────────┼──────────────┤
    │ 2.5        │ 30           │
    ├────────────┼──────────────┤
    │ 10         │ 36           │
    ├────────────┼──────────────┤
    │ 25         │ 40           │
    ├────────────┼──────────────┤
    │ 50         │ 44           │
    ├────────────┼──────────────┤
    │ 75         │ 49           │
    ├────────────┼──────────────┤
    │ 90         │ 53           │
    ├────────────┼──────────────┤
    │ 97.5       │ 59           │
    ├────────────┼──────────────┤
    │ 99         │ 63           │
    ├────────────┼──────────────┤
    │ 99.9       │ 71           │
    ├────────────┼──────────────┤
    │ 99.99      │ 77           │
    ├────────────┼──────────────┤
    │ 99.999     │ 77           │
    └────────────┴──────────────┘

    13k requests in 60.02s, 4.8 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    1,000 clients subscribed, 64.23s

    ┌──────────┬──────────┬──────────┬──────────┬─────────┬──────────┬─────────┬──────────┐
    │ Stat     │ 2.5%     │ 50%      │ 97.5%    │ 99%     │ Avg      │ Stdev   │ Max      │
    ├──────────┼──────────┼──────────┼──────────┼─────────┼──────────┼─────────┼──────────┤
    │ Delivery │ 20.86 ms │ 36.67 ms │ 52.93 ms │ 56.8 ms │ 36.73 ms │ 7.88 ms │ 77.63 ms │
    └──────────┴──────────┴──────────┴──────────┴─────────┴──────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬─────────┬─────────┬───────────┬──────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min │
    ├───────────┼────┼──────┼─────────┼─────────┼───────────┼──────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 220,766 │ 241,756 │ 212,054.7 │ 45274.23 │ 0   │
    └───────────┴────┴──────┴─────────┴─────────┴───────────┴──────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    13.33M notifications received in 64.23s (13,330,000 of 13,321,000 expected), 2045.3 MB read
    ```

**One server stops.** With 1,516,519 clients connected, API Maker was restarted on the only server : every client was closed with `1001`, waited one to five seconds, and came back to it.

Clients dropped

1,516,519

100 % of 1,516,519

All back after

221.1s

on the server, restarted

A client was away, p50

111.3s

its own wait of 1 to 5 s counted

A client was away, p99

180.7s

the longest : 189 s

They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 1.06 ms (p50) and 51.7 ms (p99). A client whose subscription had not come back with it would have been told nothing.

### 2 × 4 vCPU · 8 GB

| | |
|---|---|
| API servers | 2 × Dedicated 8 GB (g6-dedicated-4) : 4 dedicated vCPUs and 8 GB each, $144 a month in all. API Maker and its two sandboxes on each, attached to the data server by the installer (`--secondary`) |
| Data server | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM). MongoDB 8.0.10 and Redis 7.0.5 of API Maker, in Docker ; its own API Maker stopped |
| CPU | AMD EPYC 7642 48-Core Processor |
| System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 |
| API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy |
| Network limits | as the installer sets them, on every API server : 2,032,896 connections tracked (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted, 2,032,896 open files. The memory of all its TCP connections together : raised by API Maker as the clients came, to 1.9 GB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) |
| Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7642 48-Core Processor, 16 dedicated vCPUs. The clients go to the API servers in turn, as a load balancer hands them out ; autocannon calls every API server at the same time |
| Network | A VLAN of the same data centre, round trip 0.32 ms (ping) |
| Date | 14 October 2026, 03:20 to 04:00 UTC |

Clients connected

1,915,960

957,980 on each of 2 servers

Memory per client

8.8KB

API Maker 3.2 · kernel 4.5 · Redis 1.1

New clients / second

12,696

both tokens and a subscription · 21,417 without one

Notification delivered in

1.18ms

p50 at 1,000 a second · p99 1.80 ms

The run stopped adding clients at **1,915,960** : the memory of the server `api-1` was full. 1,072 MB of its 7,941 MB were still counted as available, and Linux had moved 683 MB to the swap since the clients began to connect, to make that room : 389 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server).

> Diagram : Clients connected and memory used during the run
>
> The run of this server, second after second : the WebSocket clients connected, up to 1,915,960, and the memory the server used, up to 13,978 MB of 15,882 MB.

| Clients connected | API Maker, all servers | Linux kernel, all servers | API servers, used | Least available on a server | Redis (its data) | Data server, used | CPU busy |
|---|--:|--:|--:|--:|--:|--:|--:|
| No client (at rest) | 225 MB | 338 MB | 1,341 MB | 7,262 MB | 2 MB | 703 MB | 0.3 % |
| **10,000** clients | 285 MB | 479 MB | 2,313 MB | 6,775 MB | 12 MB | 714 MB | 1.7 % |
| **100,000** clients | 564 MB | 789 MB | 2,860 MB | 6,495 MB | 103 MB | 913 MB | 1.0 % |
| **200,000** clients | 875 MB | 1,236 MB | 3,532 MB | 6,156 MB | 204 MB | 1,040 MB | 2.1 % |
| **400,000** clients | 1,529 MB | 2,131 MB | 4,936 MB | 5,452 MB | 404 MB | 1,217 MB | 3.7 % |
| **600,000** clients | 2,178 MB | 3,028 MB | 6,332 MB | 4,730 MB | 625 MB | 1,452 MB | 5.7 % |
| **800,000** clients | 2,787 MB | 3,921 MB | 7,709 MB | 4,026 MB | 810 MB | 1,637 MB | 7.6 % |
| **1,000,000** clients | 3,459 MB | 4,813 MB | 9,150 MB | 3,289 MB | 996 MB | 1,828 MB | 9.8 % |
| **1,200,000** clients | 4,065 MB | 5,696 MB | 10,517 MB | 2,585 MB | 1,249 MB | 2,093 MB | 12.1 % |
| **1,400,000** clients | 4,672 MB | 6,545 MB | 11,926 MB | 1,877 MB | 1,430 MB | 2,270 MB | 13.8 % |
| **1,600,000** clients | 5,271 MB | 7,398 MB | 12,820 MB | 1,518 MB | 1,619 MB | 2,475 MB | 16.3 % |
| **1,800,000** clients | 5,774 MB | 8,263 MB | 13,795 MB | 1,027 MB | 1,800 MB | 2,729 MB | 19.1 % |
| **1,915,960** clients | 5,569 MB | 8,758 MB | 13,708 MB | 1,051 MB | 1,910 MB | 2,781 MB | 20.1 % |

**New clients**

Clients / second

12,696

762,499 clients in 60 s, 100 at a time

Let in after, p50

6.32ms

connected 1.66 ms · TCP 0.24 ms

Let in after, p99

14.0ms

max 45.5 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **7.3 vCPU** · Redis **0.8 vCPU** · whole server busy **94 %** · load generator busy **28 %**

    am_ws_load · connect with both tokens and subscribe · 2 servers

    ```text
    $ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>" --register 'order-updates'
    Running 60s test @ ws://<server>:38246 and 1 more
    100 clients at a time : connect, CONNECTED, REGISTER, leave

    ┌─────────────┬─────────┬─────────┬──────────┬──────────┬─────────┬─────────┬──────────┐
    │ Stat        │ 2.5%    │ 50%     │ 97.5%    │ 99%      │ Avg     │ Stdev   │ Max      │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ TCP connect │ 0.18 ms │ 0.24 ms │ 0.44 ms  │ 0.53 ms  │ 0.26 ms │ 0.17 ms │ 10.98 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ CONNECTED   │ 0.64 ms │ 1.66 ms │ 4.39 ms  │ 4.95 ms  │ 1.95 ms │ 1.08 ms │ 19.33 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ REGISTER    │ 2.53 ms │ 6.32 ms │ 13.06 ms │ 13.98 ms │ 6.89 ms │ 3.44 ms │ 45.54 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ Left        │ 2.92 ms │ 7.32 ms │ 14.71 ms │ 15.74 ms │ 7.85 ms │ 3.93 ms │ 47.58 ms │
    └─────────────┴─────────┴─────────┴──────────┴──────────┴─────────┴─────────┴──────────┘
    ┌─────────────┬────────┬────────┬────────┬────────┬──────────┬────────┬────────┐
    │ Stat        │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg      │ Stdev  │ Min    │
    ├─────────────┼────────┼────────┼────────┼────────┼──────────┼────────┼────────┤
    │ Clients/Sec │ 11,195 │ 11,486 │ 12,765 │ 13,261 │ 12,708.3 │ 364.16 │ 11,195 │
    └─────────────┴────────┴────────┴────────┴────────┴──────────┴────────┴────────┘

    Time from the start of the connection to each step. Clients counted once per second.
    # of samples: 60

    762k clients let in in 60.06s, 0 refused or lost
    ```

**One person, 1,000 a second**

Calls / second (paced)

1,000

60,004 calls in 60 s, 10 connections

Notifications / second

984

60,014 received by 10,000 clients

Delivery p50

1.18ms

average 1.19 ms

Delivery p99

1.80ms

max 10.0 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **0.4 vCPU** · Redis **0.1 vCPU** · whole server busy **5 %** · load generator busy **3 %**

    autocannon · A notification for one person, 1,000 a second · server 1 of 2

    ```text
    $ autocannon -c 5 -d 60 -R 500 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    5 connections

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
    │ Latency │ 0 ms │ 1 ms │ 1 ms  │ 2 ms │ 0.87 ms │ 0.47 ms │ 10 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
    ┌───────────┬────────┬────────┬────────┬────────┬────────┬───────┬────────┐
    │ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev │ Min    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Req/Sec   │ 499    │ 499    │ 500    │ 501    │ 500    │ 0.37  │ 499    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Bytes/Sec │ 178 kB │ 178 kB │ 179 kB │ 179 kB │ 178 kB │ 140 B │ 178 kB │
    └───────────┴────────┴────────┴────────┴────────┴────────┴───────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 0            │
    ├────────────┼──────────────┤
    │ 10         │ 0            │
    ├────────────┼──────────────┤
    │ 25         │ 1            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 1            │
    ├────────────┼──────────────┤
    │ 90         │ 1            │
    ├────────────┼──────────────┤
    │ 97.5       │ 1            │
    ├────────────┼──────────────┤
    │ 99         │ 2            │
    ├────────────┼──────────────┤
    │ 99.9       │ 5            │
    ├────────────┼──────────────┤
    │ 99.99      │ 9            │
    ├────────────┼──────────────┤
    │ 99.999     │ 10           │
    └────────────┴──────────────┘

    31k requests in 60.01s, 10.7 MB read
    ```

    autocannon · A notification for one person, 1,000 a second · server 2 of 2

    ```text
    $ autocannon -c 5 -d 60 -R 500 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    5 connections

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬──────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max  │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼──────┤
    │ Latency │ 0 ms │ 1 ms │ 1 ms  │ 1 ms │ 0.96 ms │ 0.33 ms │ 9 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴──────┘
    ┌───────────┬────────┬────────┬────────┬────────┬────────┬───────┬────────┐
    │ Stat      │ 1%     │ 2.5%   │ 50%    │ 97.5%  │ Avg    │ Stdev │ Min    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Req/Sec   │ 497    │ 499    │ 500    │ 502    │ 500.07 │ 0.63  │ 497    │
    ├───────────┼────────┼────────┼────────┼────────┼────────┼───────┼────────┤
    │ Bytes/Sec │ 178 kB │ 178 kB │ 179 kB │ 179 kB │ 179 kB │ 231 B │ 177 kB │
    └───────────┴────────┴────────┴────────┴────────┴────────┴───────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 0            │
    ├────────────┼──────────────┤
    │ 10         │ 1            │
    ├────────────┼──────────────┤
    │ 25         │ 1            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 1            │
    ├────────────┼──────────────┤
    │ 90         │ 1            │
    ├────────────┼──────────────┤
    │ 97.5       │ 1            │
    ├────────────┼──────────────┤
    │ 99         │ 1            │
    ├────────────┼──────────────┤
    │ 99.9       │ 4            │
    ├────────────┼──────────────┤
    │ 99.99      │ 9            │
    ├────────────┼──────────────┤
    │ 99.999     │ 9            │
    └────────────┴──────────────┘

    31k requests in 60.01s, 10.7 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 64.03s

    ┌──────────┬─────────┬─────────┬─────────┬────────┬─────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%   │ 99%    │ Avg     │ Stdev   │ Max      │
    ├──────────┼─────────┼─────────┼─────────┼────────┼─────────┼─────────┼──────────┤
    │ Delivery │ 0.83 ms │ 1.18 ms │ 1.63 ms │ 1.8 ms │ 1.19 ms │ 0.28 ms │ 10.04 ms │
    └──────────┴─────────┴─────────┴─────────┴────────┴─────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬───────┬───────┬───────┬────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5% │ Avg   │ Stdev  │ Min │
    ├───────────┼────┼──────┼───────┼───────┼───────┼────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 1,000 │ 1,000 │ 951.8 │ 213.59 │ 0   │
    └───────────┴────┴──────┴───────┴───────┴───────┴────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    60k notifications received in 64.03s (60,014 of 60,004 expected), 10.7 MB read
    ```

**One person, as many as the servers take**

Calls / second

25,389

1,523,298 calls in 60 s, 100 connections

Notifications / second

24,977

1,523,398 received by 10,000 clients

Delivery p50

3.75ms

average 3.95 ms

Delivery p99

6.31ms

max 530 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **7.8 vCPU** · Redis **0.6 vCPU** · whole server busy **99 %** · load generator busy **46 %**

    autocannon · A notification for one person, as many as the server takes · server 1 of 2

    ```text
    $ autocannon -c 50 -d 60 -w 10 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    50 connections
    10 workers

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max    │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤
    │ Latency │ 2 ms │ 3 ms │ 5 ms  │ 5 ms │ 2.96 ms │ 1.47 ms │ 531 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬───────────┬────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg       │ Stdev  │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼────────┼─────────┤
    │ Req/Sec   │ 10,431  │ 13,639  │ 14,215  │ 15,439  │ 14,278.94 │ 663.06 │ 10,426  │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼───────────┼────────┼─────────┤
    │ Bytes/Sec │ 3.72 MB │ 4.87 MB │ 5.07 MB │ 5.51 MB │ 5.1 MB    │ 237 kB │ 3.72 MB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴───────────┴────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 1            │
    ├────────────┼──────────────┤
    │ 2.5        │ 2            │
    ├────────────┼──────────────┤
    │ 10         │ 2            │
    ├────────────┼──────────────┤
    │ 25         │ 2            │
    ├────────────┼──────────────┤
    │ 50         │ 3            │
    ├────────────┼──────────────┤
    │ 75         │ 3            │
    ├────────────┼──────────────┤
    │ 90         │ 4            │
    ├────────────┼──────────────┤
    │ 97.5       │ 5            │
    ├────────────┼──────────────┤
    │ 99         │ 5            │
    ├────────────┼──────────────┤
    │ 99.9       │ 9            │
    ├────────────┼──────────────┤
    │ 99.99      │ 16           │
    ├────────────┼──────────────┤
    │ 99.999     │ 209          │
    └────────────┴──────────────┘

    857k requests in 60.02s, 306 MB read
    ```

    autocannon · A notification for one person, as many as the server takes · server 2 of 2

    ```text
    $ autocannon -c 50 -d 60 -w 10 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    50 connections
    10 workers

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬────────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max    │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼────────┤
    │ Latency │ 2 ms │ 4 ms │ 6 ms  │ 6 ms │ 3.96 ms │ 1.31 ms │ 525 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴────────┘
    ┌───────────┬─────────┬─────────┬─────────┬────────┬─────────┬────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%  │ Avg     │ Stdev  │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼────────┼─────────┤
    │ Req/Sec   │ 10,527  │ 10,559  │ 10,983  │ 11,759 │ 11,110  │ 330.41 │ 10,525  │
    ├───────────┼─────────┼─────────┼─────────┼────────┼─────────┼────────┼─────────┤
    │ Bytes/Sec │ 3.76 MB │ 3.77 MB │ 3.92 MB │ 4.2 MB │ 3.97 MB │ 118 kB │ 3.76 MB │
    └───────────┴─────────┴─────────┴─────────┴────────┴─────────┴────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 600

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 2            │
    ├────────────┼──────────────┤
    │ 2.5        │ 2            │
    ├────────────┼──────────────┤
    │ 10         │ 3            │
    ├────────────┼──────────────┤
    │ 25         │ 3            │
    ├────────────┼──────────────┤
    │ 50         │ 4            │
    ├────────────┼──────────────┤
    │ 75         │ 5            │
    ├────────────┼──────────────┤
    │ 90         │ 5            │
    ├────────────┼──────────────┤
    │ 97.5       │ 6            │
    ├────────────┼──────────────┤
    │ 99         │ 6            │
    ├────────────┼──────────────┤
    │ 99.9       │ 7            │
    ├────────────┼──────────────┤
    │ 99.99      │ 20           │
    ├────────────┼──────────────┤
    │ 99.999     │ 55           │
    └────────────┴──────────────┘

    667k requests in 60.02s, 238 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 64.00s

    ┌──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max       │
    ├──────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────────┤
    │ Delivery │ 2.12 ms │ 3.75 ms │ 5.85 ms │ 6.31 ms │ 3.95 ms │ 7.32 ms │ 529.92 ms │
    └──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────────┘
    ┌───────────┬────┬──────┬────────┬────────┬──────────┬─────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%    │ 97.5%  │ Avg      │ Stdev   │ Min │
    ├───────────┼────┼──────┼────────┼────────┼──────────┼─────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 25,431 │ 26,179 │ 24,446.4 │ 4538.65 │ 0   │
    └───────────┴────┴──────┴────────┴────────┴──────────┴─────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    1.52M notifications received in 64.00s (1,523,398 of 1,523,298 expected), 272.8 MB read
    ```

**Broadcast, as many as the servers take**

Calls / second

255

15,275 calls in 60 s, 10 connections

Notifications / second

228,910

15,285,000 received by 1,000 clients

Delivery p50

39.3ms

average 1,295 ms

Delivery p99

6,701ms

max 6,902 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **7.2 vCPU** · Redis **0.6 vCPU** · whole server busy **91 %** · load generator busy **32 %**

(Told for 66.8 s) The calls came faster than the server tells its clients : it went on telling them for **5.5 s** after the calls stopped, and API Maker held up to **594 MB** while they waited. Notifications per second counts the whole of that time ; the delivery times are the times of notifications which waited their turn.

    autocannon · A broadcast to 1,000 clients, as many as the server takes · server 1 of 2

    ```text
    $ autocannon -c 5 -d 60 -w 5 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    5 connections
    5 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬────────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max    │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼────────┤
    │ Latency │ 21 ms │ 33 ms │ 48 ms │ 52 ms │ 33.22 ms │ 7.25 ms │ 103 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴────────┘
    ┌───────────┬─────────┬───────┬─────────┬─────────┬─────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%  │ 50%     │ 97.5%   │ Avg     │ Stdev   │ Min     │
    ├───────────┼─────────┼───────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Req/Sec   │ 137     │ 139   │ 146     │ 159     │ 147.87  │ 6.08    │ 137     │
    ├───────────┼─────────┼───────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Bytes/Sec │ 49.3 kB │ 50 kB │ 52.6 kB │ 57.2 kB │ 53.2 kB │ 2.19 kB │ 49.3 kB │
    └───────────┴─────────┴───────┴─────────┴─────────┴─────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 300

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 8            │
    ├────────────┼──────────────┤
    │ 0.01       │ 8            │
    ├────────────┼──────────────┤
    │ 0.1        │ 14           │
    ├────────────┼──────────────┤
    │ 1          │ 19           │
    ├────────────┼──────────────┤
    │ 2.5        │ 21           │
    ├────────────┼──────────────┤
    │ 10         │ 24           │
    ├────────────┼──────────────┤
    │ 25         │ 28           │
    ├────────────┼──────────────┤
    │ 50         │ 33           │
    ├────────────┼──────────────┤
    │ 75         │ 38           │
    ├────────────┼──────────────┤
    │ 90         │ 43           │
    ├────────────┼──────────────┤
    │ 97.5       │ 48           │
    ├────────────┼──────────────┤
    │ 99         │ 52           │
    ├────────────┼──────────────┤
    │ 99.9       │ 65           │
    ├────────────┼──────────────┤
    │ 99.99      │ 103          │
    ├────────────┼──────────────┤
    │ 99.999     │ 103          │
    └────────────┴──────────────┘

    9k requests in 60.01s, 3.19 MB read
    ```

    autocannon · A broadcast to 1,000 clients, as many as the server takes · server 2 of 2

    ```text
    $ autocannon -c 5 -d 60 -w 5 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    5 connections
    5 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬───────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev    │ Max   │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼───────┤
    │ Latency │ 28 ms │ 46 ms │ 69 ms │ 73 ms │ 46.24 ms │ 10.24 ms │ 98 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴───────┘
    ┌───────────┬─────────┬───────┬─────────┬─────────┬─────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%  │ 50%     │ 97.5%   │ Avg     │ Stdev   │ Min     │
    ├───────────┼─────────┼───────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Req/Sec   │ 98      │ 100   │ 106     │ 115     │ 106.72  │ 4.2     │ 98      │
    ├───────────┼─────────┼───────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Bytes/Sec │ 35.3 kB │ 36 kB │ 38.2 kB │ 41.4 kB │ 38.4 kB │ 1.51 kB │ 35.3 kB │
    └───────────┴─────────┴───────┴─────────┴─────────┴─────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 300

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 19           │
    ├────────────┼──────────────┤
    │ 0.01       │ 19           │
    ├────────────┼──────────────┤
    │ 0.1        │ 20           │
    ├────────────┼──────────────┤
    │ 1          │ 25           │
    ├────────────┼──────────────┤
    │ 2.5        │ 28           │
    ├────────────┼──────────────┤
    │ 10         │ 34           │
    ├────────────┼──────────────┤
    │ 25         │ 39           │
    ├────────────┼──────────────┤
    │ 50         │ 46           │
    ├────────────┼──────────────┤
    │ 75         │ 53           │
    ├────────────┼──────────────┤
    │ 90         │ 60           │
    ├────────────┼──────────────┤
    │ 97.5       │ 69           │
    ├────────────┼──────────────┤
    │ 99         │ 73           │
    ├────────────┼──────────────┤
    │ 99.9       │ 84           │
    ├────────────┼──────────────┤
    │ 99.99      │ 98           │
    ├────────────┼──────────────┤
    │ 99.999     │ 98           │
    └────────────┴──────────────┘

    6k requests in 60.02s, 2.31 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    1,000 clients subscribed, 69.78s

    ┌──────────┬──────────┬─────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
    │ Stat     │ 2.5%     │ 50%     │ 97.5%      │ 99%        │ Avg        │ Stdev      │ Max        │
    ├──────────┼──────────┼─────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
    │ Delivery │ 14.95 ms │ 39.3 ms │ 6590.46 ms │ 6701.06 ms │ 1295.23 ms │ 2293.94 ms │ 6901.76 ms │
    └──────────┴──────────┴─────────┴────────────┴────────────┴────────────┴────────────┴────────────┘
    ┌───────────┬────┬──────┬─────────┬─────────┬───────────┬──────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min │
    ├───────────┼────┼──────┼─────────┼─────────┼───────────┼──────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 244,237 │ 256,512 │ 223,239.3 │ 62807.61 │ 0   │
    └───────────┴────┴──────┴─────────┴─────────┴───────────┴──────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 70

    15.29M notifications received in 69.78s (15,285,000 of 15,275,000 expected), 2345.2 MB read
    ```

**One server stops.** Nobody runs a cluster full : the servers which are left need room for the clients of the one which stops. So the newest clients left first, down to **766,384** : what 1 of the 2 servers hold when each of them is 80 % full. API Maker was then stopped on one of the servers (`systemctl stop api_maker_be`) and stayed down : its clients were closed with `1001`, waited one to five seconds, and connected to the servers which were left.

Clients dropped

383,192

50 % of 766,384

All back after

68.0s

on the 1 server left

A client was away, p50

36.4s

its own wait of 1 to 5 s counted

A client was away, p99

55.8s

the longest : 57.9 s

They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,002 arrived**, in 1.85 ms (p50) and 144 ms (p99). A client whose subscription had not come back with it would have been told nothing.

### 4 × 2 vCPU · 4 GB

| | |
|---|---|
| API servers | 4 × Dedicated 4 GB (g6-dedicated-2) : 2 dedicated vCPUs and 4 GB each, $144 a month in all. API Maker and its two sandboxes on each, attached to the data server by the installer (`--secondary`) |
| Data server | Dedicated 8 GB (g6-dedicated-4) : AMD EPYC 7642 48-Core Processor, 4 dedicated vCPUs (KVM). MongoDB 8.0.10 and Redis 7.0.5 of API Maker, in Docker ; its own API Maker stopped |
| CPU | AMD EPYC 7642 48-Core Processor · AMD EPYC 7713 64-Core Processor |
| System | Ubuntu 24.04.4 LTS, Linux 6.8.0-134, Docker 29.9.0 |
| API Maker | 4.0.0 : release build of api_maker_be_rust 423a34c with the new WebSocket core of 14 October 2026 (opt-level 3, fat LTO), installed by its installer (https://apimaker.dev/v4/install.sh), no reverse proxy |
| Network limits | as the installer sets them, on every API server : 1,002,240 connections tracked (`net.netfilter.nf_conntrack_max`), 16,384 waiting to be accepted, 1,048,576 open files. The memory of all its TCP connections together : raised by API Maker as the clients came, to 979 MB at the most (`net.ipv4.tcp_mem`, 25 % of the memory ; Linux gives 9 %) |
| Load generator | Dedicated 32 GB (g6-dedicated-16) : AMD EPYC 7713 64-Core Processor, 16 dedicated vCPUs. The clients go to the API servers in turn, as a load balancer hands them out ; autocannon calls every API server at the same time |
| Network | A VLAN of the same data centre, round trip 0.51 ms (ping) |
| Date | 14 October 2026, 03:26 to 04:05 UTC |

Clients connected

1,619,372

404,843 on each of 4 servers

Memory per client

8.6KB

API Maker 3.2 · kernel 4.4 · Redis 1.1

New clients / second

10,297

both tokens and a subscription · 17,882 without one

Notification delivered in

1.37ms

p50 at 1,000 a second · p99 2.51 ms

The run stopped adding clients at **1,619,372** : the memory of the server `api-2` was full. 456 MB of its 3,916 MB were still counted as available, and Linux had moved 266 MB to the swap since the clients began to connect, to make that room : 190 MB were left (the run stops when what is available, less what Linux moved to the swap since the clients began to connect, is under 5 % of the memory of the server).

> Diagram : Clients connected and memory used during the run
>
> The run of this server, second after second : the WebSocket clients connected, up to 1,619,372, and the memory the server used, up to 13,792 MB of 15,660 MB.

| Clients connected | API Maker, all servers | Linux kernel, all servers | API servers, used | Least available on a server | Redis (its data) | Data server, used | CPU busy |
|---|--:|--:|--:|--:|--:|--:|--:|
| No client (at rest) | 417 MB | 630 MB | 2,478 MB | 3,288 MB | 2 MB | 721 MB | 0.7 % |
| **10,000** clients | 491 MB | 749 MB | 3,088 MB | 3,115 MB | 12 MB | 718 MB | 1.6 % |
| **100,000** clients | 790 MB | 1,079 MB | 3,710 MB | 2,954 MB | 103 MB | 906 MB | 1.2 % |
| **200,000** clients | 1,091 MB | 1,527 MB | 4,440 MB | 2,775 MB | 204 MB | 1,023 MB | 2.1 % |
| **400,000** clients | 1,734 MB | 2,421 MB | 5,911 MB | 2,392 MB | 404 MB | 1,204 MB | 4.4 % |
| **600,000** clients | 2,388 MB | 3,305 MB | 7,358 MB | 2,016 MB | 625 MB | 1,459 MB | 6.1 % |
| **800,000** clients | 2,995 MB | 4,155 MB | 8,723 MB | 1,665 MB | 810 MB | 1,628 MB | 7.8 % |
| **1,000,000** clients | 3,673 MB | 5,006 MB | 10,180 MB | 1,301 MB | 996 MB | 1,815 MB | 9.6 % |
| **1,200,000** clients | 4,280 MB | 5,864 MB | 11,512 MB | 941 MB | 1,249 MB | 2,077 MB | 11.8 % |
| **1,400,000** clients | 4,790 MB | 6,713 MB | 12,967 MB | 567 MB | 1,430 MB | 2,265 MB | 14.9 % |
| **1,600,000** clients | 5,079 MB | 7,560 MB | 13,681 MB | 455 MB | 1,619 MB | 2,450 MB | 16.3 % |
| **1,619,372** clients | 5,077 MB | 7,645 MB | 13,764 MB | 454 MB | 1,638 MB | 2,490 MB | 16.2 % |

**New clients**

Clients / second

10,297

618,456 clients in 60 s, 100 at a time

Let in after, p50

3.91ms

connected 1.12 ms · TCP 0.34 ms

Let in after, p99

30.2ms

max 53.5 ms

Refused or lost

0

not connected, not subscribed, no answer

(Server during this run) API Maker **6.6 vCPU** · Redis **1.0 vCPU** · whole server busy **88 %** · load generator busy **29 %**

    am_ws_load · connect with both tokens and subscribe · 4 servers

    ```text
    $ am_ws_load churn -c 100 -d 60 "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>" --register 'order-updates'
    Running 60s test @ ws://<server>:38246 and 3 more
    100 clients at a time : connect, CONNECTED, REGISTER, leave

    ┌─────────────┬─────────┬─────────┬──────────┬──────────┬─────────┬─────────┬──────────┐
    │ Stat        │ 2.5%    │ 50%     │ 97.5%    │ 99%      │ Avg     │ Stdev   │ Max      │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ TCP connect │ 0.22 ms │ 0.34 ms │ 0.65 ms  │ 0.88 ms  │ 0.38 ms │ 0.31 ms │ 20.11 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ CONNECTED   │ 0.75 ms │ 1.12 ms │ 7.89 ms  │ 8.79 ms  │ 2.22 ms │ 2.19 ms │ 30.96 ms │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ REGISTER    │ 2.63 ms │ 3.91 ms │ 28.11 ms │ 30.19 ms │ 8.45 ms │ 8.48 ms │ 53.5 ms  │
    ├─────────────┼─────────┼─────────┼──────────┼──────────┼─────────┼─────────┼──────────┤
    │ Left        │ 3.04 ms │ 4.39 ms │ 31.98 ms │ 34.34 ms │ 9.68 ms │ 9.77 ms │ 55.1 ms  │
    └─────────────┴─────────┴─────────┴──────────┴──────────┴─────────┴─────────┴──────────┘
    ┌─────────────┬───────┬───────┬────────┬────────┬──────────┬────────┬───────┐
    │ Stat        │ 1%    │ 2.5%  │ 50%    │ 97.5%  │ Avg      │ Stdev  │ Min   │
    ├─────────────┼───────┼───────┼────────┼────────┼──────────┼────────┼───────┤
    │ Clients/Sec │ 9,718 │ 9,725 │ 10,283 │ 11,091 │ 10,307.6 │ 350.49 │ 9,718 │
    └─────────────┴───────┴───────┴────────┴────────┴──────────┴────────┴───────┘

    Time from the start of the connection to each step. Clients counted once per second.
    # of samples: 60

    618k clients let in in 60.06s, 0 refused or lost
    ```

**One person, 1,000 a second**

Calls / second (paced)

1,000

60,000 calls in 60 s, 8 connections

Notifications / second

983

60,003 received by 10,000 clients

Delivery p50

1.37ms

average 1.44 ms

Delivery p99

2.51ms

max 12.2 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **0.4 vCPU** · Redis **0.1 vCPU** · whole server busy **5 %** · load generator busy **4 %**

    autocannon · A notification for one person, 1,000 a second · server 1 of 4

    ```text
    $ autocannon -c 2 -d 60 -R 250 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections

    ┌─────────┬──────┬──────┬───────┬──────┬──────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg  │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼──────┼─────────┼───────┤
    │ Latency │ 0 ms │ 1 ms │ 2 ms  │ 2 ms │ 1 ms │ 0.47 ms │ 12 ms │
    └─────────┴──────┴──────┴───────┴──────┴──────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┼─────────┤
    │ Req/Sec   │ 250     │ 250     │ 250     │ 250     │ 250     │ 0     │ 250     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┼─────────┤
    │ Bytes/Sec │ 89.3 kB │ 89.3 kB │ 89.3 kB │ 89.3 kB │ 89.2 kB │ 0 B   │ 89.3 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 0            │
    ├────────────┼──────────────┤
    │ 10         │ 1            │
    ├────────────┼──────────────┤
    │ 25         │ 1            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 1            │
    ├────────────┼──────────────┤
    │ 90         │ 1            │
    ├────────────┼──────────────┤
    │ 97.5       │ 2            │
    ├────────────┼──────────────┤
    │ 99         │ 2            │
    ├────────────┼──────────────┤
    │ 99.9       │ 7            │
    ├────────────┼──────────────┤
    │ 99.99      │ 11           │
    ├────────────┼──────────────┤
    │ 99.999     │ 12           │
    └────────────┴──────────────┘

    15k requests in 60.03s, 5.36 MB read
    ```

    autocannon · A notification for one person, 1,000 a second · server 2 of 4

    ```text
    $ autocannon -c 2 -d 60 -R 250 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
    │ Latency │ 1 ms │ 1 ms │ 2 ms  │ 3 ms │ 1.34 ms │ 0.64 ms │ 12 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
    │ Req/Sec   │ 249     │ 250     │ 250     │ 250     │ 250     │ 0.19   │ 249     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
    │ Bytes/Sec │ 88.9 kB │ 89.3 kB │ 89.3 kB │ 89.3 kB │ 89.2 kB │ 70.1 B │ 88.9 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 1            │
    ├────────────┼──────────────┤
    │ 2.5        │ 1            │
    ├────────────┼──────────────┤
    │ 10         │ 1            │
    ├────────────┼──────────────┤
    │ 25         │ 1            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 2            │
    ├────────────┼──────────────┤
    │ 90         │ 2            │
    ├────────────┼──────────────┤
    │ 97.5       │ 2            │
    ├────────────┼──────────────┤
    │ 99         │ 3            │
    ├────────────┼──────────────┤
    │ 99.9       │ 9            │
    ├────────────┼──────────────┤
    │ 99.99      │ 11           │
    ├────────────┼──────────────┤
    │ 99.999     │ 12           │
    └────────────┴──────────────┘

    15k requests in 60.03s, 5.36 MB read
    ```

    autocannon · A notification for one person, 1,000 a second · server 3 of 4

    ```text
    $ autocannon -c 2 -d 60 -R 250 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬──────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max  │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼──────┤
    │ Latency │ 0 ms │ 1 ms │ 1 ms  │ 2 ms │ 0.99 ms │ 0.36 ms │ 8 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴──────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┼─────────┤
    │ Req/Sec   │ 250     │ 250     │ 250     │ 250     │ 250     │ 0     │ 250     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┼─────────┤
    │ Bytes/Sec │ 89.3 kB │ 89.3 kB │ 89.3 kB │ 89.3 kB │ 89.2 kB │ 0 B   │ 89.3 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 0            │
    ├────────────┼──────────────┤
    │ 10         │ 1            │
    ├────────────┼──────────────┤
    │ 25         │ 1            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 1            │
    ├────────────┼──────────────┤
    │ 90         │ 1            │
    ├────────────┼──────────────┤
    │ 97.5       │ 1            │
    ├────────────┼──────────────┤
    │ 99         │ 2            │
    ├────────────┼──────────────┤
    │ 99.9       │ 5            │
    ├────────────┼──────────────┤
    │ 99.99      │ 8            │
    ├────────────┼──────────────┤
    │ 99.999     │ 8            │
    └────────────┴──────────────┘

    15k requests in 60.03s, 5.36 MB read
    ```

    autocannon · A notification for one person, 1,000 a second · server 4 of 4

    ```text
    $ autocannon -c 2 -d 60 -R 250 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬──────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max  │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼──────┤
    │ Latency │ 0 ms │ 1 ms │ 1 ms  │ 2 ms │ 1.01 ms │ 0.33 ms │ 8 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴──────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┼─────────┤
    │ Req/Sec   │ 250     │ 250     │ 250     │ 250     │ 250     │ 0     │ 250     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┼─────────┤
    │ Bytes/Sec │ 89.3 kB │ 89.3 kB │ 89.3 kB │ 89.3 kB │ 89.2 kB │ 0 B   │ 89.3 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 60

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 0            │
    ├────────────┼──────────────┤
    │ 0.01       │ 0            │
    ├────────────┼──────────────┤
    │ 0.1        │ 0            │
    ├────────────┼──────────────┤
    │ 1          │ 0            │
    ├────────────┼──────────────┤
    │ 2.5        │ 0            │
    ├────────────┼──────────────┤
    │ 10         │ 1            │
    ├────────────┼──────────────┤
    │ 25         │ 1            │
    ├────────────┼──────────────┤
    │ 50         │ 1            │
    ├────────────┼──────────────┤
    │ 75         │ 1            │
    ├────────────┼──────────────┤
    │ 90         │ 1            │
    ├────────────┼──────────────┤
    │ 97.5       │ 1            │
    ├────────────┼──────────────┤
    │ 99         │ 2            │
    ├────────────┼──────────────┤
    │ 99.9       │ 5            │
    ├────────────┼──────────────┤
    │ 99.99      │ 8            │
    ├────────────┼──────────────┤
    │ 99.999     │ 8            │
    └────────────┴──────────────┘

    15k requests in 60.03s, 5.36 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 64.06s

    ┌──────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%     │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max      │
    ├──────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
    │ Delivery │ 0.91 ms │ 1.37 ms │ 2.25 ms │ 2.51 ms │ 1.44 ms │ 0.42 ms │ 12.21 ms │
    └──────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬───────┬───────┬───────┬────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%   │ 97.5% │ Avg   │ Stdev  │ Min │
    ├───────────┼────┼──────┼───────┼───────┼───────┼────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 1,000 │ 1,000 │ 951.7 │ 214.37 │ 0   │
    └───────────┴────┴──────┴───────┴───────┴───────┴────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    60k notifications received in 64.06s (60,003 of 60,000 expected), 10.7 MB read
    ```

**One person, as many as the servers take**

Calls / second

25,997

1,559,712 calls in 60 s, 100 connections

Notifications / second

25,566

1,559,812 received by 10,000 clients

Delivery p50

3.70ms

average 3.77 ms

Delivery p99

6.54ms

max 26.1 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **7.8 vCPU** · Redis **0.9 vCPU** · whole server busy **99 %** · load generator busy **64 %**

    autocannon · A notification for one person, as many as the server takes · server 1 of 4

    ```text
    $ autocannon -c 25 -d 60 -w 5 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    25 connections
    5 workers

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
    │ Latency │ 2 ms │ 3 ms │ 4 ms  │ 5 ms │ 3.17 ms │ 0.81 ms │ 21 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬────────┬─────────┬──────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%    │ 97.5%   │ Avg      │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼────────┼─────────┼──────────┼─────────┼─────────┤
    │ Req/Sec   │ 5,751   │ 6,175   │ 6,719  │ 7,035   │ 6,726.14 │ 213.6   │ 5,750   │
    ├───────────┼─────────┼─────────┼────────┼─────────┼──────────┼─────────┼─────────┤
    │ Bytes/Sec │ 2.05 MB │ 2.21 MB │ 2.4 MB │ 2.51 MB │ 2.4 MB   │ 76.2 kB │ 2.05 MB │
    └───────────┴─────────┴─────────┴────────┴─────────┴──────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 300

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 2            │
    ├────────────┼──────────────┤
    │ 2.5        │ 2            │
    ├────────────┼──────────────┤
    │ 10         │ 2            │
    ├────────────┼──────────────┤
    │ 25         │ 3            │
    ├────────────┼──────────────┤
    │ 50         │ 3            │
    ├────────────┼──────────────┤
    │ 75         │ 4            │
    ├────────────┼──────────────┤
    │ 90         │ 4            │
    ├────────────┼──────────────┤
    │ 97.5       │ 4            │
    ├────────────┼──────────────┤
    │ 99         │ 5            │
    ├────────────┼──────────────┤
    │ 99.9       │ 9            │
    ├────────────┼──────────────┤
    │ 99.99      │ 14           │
    ├────────────┼──────────────┤
    │ 99.999     │ 18           │
    └────────────┴──────────────┘

    404k requests in 60.02s, 144 MB read
    ```

    autocannon · A notification for one person, as many as the server takes · server 2 of 4

    ```text
    $ autocannon -c 25 -d 60 -w 5 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    25 connections
    5 workers

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
    │ Latency │ 3 ms │ 5 ms │ 7 ms  │ 8 ms │ 4.64 ms │ 1.26 ms │ 27 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
    │ Req/Sec   │ 3,993   │ 4,407   │ 4,807   │ 5,259   │ 4,823.25 │ 228.72  │ 3,993   │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
    │ Bytes/Sec │ 1.43 MB │ 1.57 MB │ 1.72 MB │ 1.88 MB │ 1.72 MB  │ 81.7 kB │ 1.43 MB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 300

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 2            │
    ├────────────┼──────────────┤
    │ 1          │ 2            │
    ├────────────┼──────────────┤
    │ 2.5        │ 3            │
    ├────────────┼──────────────┤
    │ 10         │ 3            │
    ├────────────┼──────────────┤
    │ 25         │ 4            │
    ├────────────┼──────────────┤
    │ 50         │ 5            │
    ├────────────┼──────────────┤
    │ 75         │ 5            │
    ├────────────┼──────────────┤
    │ 90         │ 6            │
    ├────────────┼──────────────┤
    │ 97.5       │ 7            │
    ├────────────┼──────────────┤
    │ 99         │ 8            │
    ├────────────┼──────────────┤
    │ 99.9       │ 14           │
    ├────────────┼──────────────┤
    │ 99.99      │ 21           │
    ├────────────┼──────────────┤
    │ 99.999     │ 26           │
    └────────────┴──────────────┘

    289k requests in 60.02s, 103 MB read
    ```

    autocannon · A notification for one person, as many as the server takes · server 3 of 4

    ```text
    $ autocannon -c 25 -d 60 -w 5 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    25 connections
    5 workers

    ┌─────────┬──────┬──────┬───────┬──────┬─────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg     │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼─────────┼─────────┼───────┤
    │ Latency │ 2 ms │ 3 ms │ 4 ms  │ 4 ms │ 2.91 ms │ 0.72 ms │ 22 ms │
    └─────────┴──────┴──────┴───────┴──────┴─────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
    │ Req/Sec   │ 6,267   │ 6,859   │ 7,231   │ 7,443   │ 7,218.94 │ 198.19  │ 6,265   │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
    │ Bytes/Sec │ 2.24 MB │ 2.45 MB │ 2.58 MB │ 2.66 MB │ 2.58 MB  │ 70.7 kB │ 2.24 MB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 300

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 1            │
    ├────────────┼──────────────┤
    │ 2.5        │ 2            │
    ├────────────┼──────────────┤
    │ 10         │ 2            │
    ├────────────┼──────────────┤
    │ 25         │ 2            │
    ├────────────┼──────────────┤
    │ 50         │ 3            │
    ├────────────┼──────────────┤
    │ 75         │ 3            │
    ├────────────┼──────────────┤
    │ 90         │ 4            │
    ├────────────┼──────────────┤
    │ 97.5       │ 4            │
    ├────────────┼──────────────┤
    │ 99         │ 4            │
    ├────────────┼──────────────┤
    │ 99.9       │ 7            │
    ├────────────┼──────────────┤
    │ 99.99      │ 12           │
    ├────────────┼──────────────┤
    │ 99.999     │ 19           │
    └────────────┴──────────────┘

    433k requests in 60.02s, 155 MB read
    ```

    autocannon · A notification for one person, as many as the server takes · server 4 of 4

    ```text
    $ autocannon -c 25 -d 60 -w 5 -l -m POST -b '{"name":"order-updates","eventData":{"recipientId":"<id of a client>","t":<now>,"type":"order-updated","order_no":1001,"status":"SHIPPED"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    25 connections
    5 workers

    ┌─────────┬──────┬──────┬───────┬──────┬────────┬─────────┬───────┐
    │ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%  │ Avg    │ Stdev   │ Max   │
    ├─────────┼──────┼──────┼───────┼──────┼────────┼─────────┼───────┤
    │ Latency │ 2 ms │ 3 ms │ 4 ms  │ 4 ms │ 2.9 ms │ 0.71 ms │ 27 ms │
    └─────────┴──────┴──────┴───────┴──────┴────────┴─────────┴───────┘
    ┌───────────┬────────┬─────────┬─────────┬─────────┬──────────┬─────────┬────────┐
    │ Stat      │ 1%     │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev   │ Min    │
    ├───────────┼────────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┤
    │ Req/Sec   │ 6,451  │ 6,987   │ 7,247   │ 7,327   │ 7,228.94 │ 122.08  │ 6,449  │
    ├───────────┼────────┼─────────┼─────────┼─────────┼──────────┼─────────┼────────┤
    │ Bytes/Sec │ 2.3 MB │ 2.49 MB │ 2.59 MB │ 2.62 MB │ 2.58 MB  │ 43.5 kB │ 2.3 MB │
    └───────────┴────────┴─────────┴─────────┴─────────┴──────────┴─────────┴────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 300

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 1            │
    ├────────────┼──────────────┤
    │ 0.01       │ 1            │
    ├────────────┼──────────────┤
    │ 0.1        │ 1            │
    ├────────────┼──────────────┤
    │ 1          │ 2            │
    ├────────────┼──────────────┤
    │ 2.5        │ 2            │
    ├────────────┼──────────────┤
    │ 10         │ 2            │
    ├────────────┼──────────────┤
    │ 25         │ 2            │
    ├────────────┼──────────────┤
    │ 50         │ 3            │
    ├────────────┼──────────────┤
    │ 75         │ 3            │
    ├────────────┼──────────────┤
    │ 90         │ 4            │
    ├────────────┼──────────────┤
    │ 97.5       │ 4            │
    ├────────────┼──────────────┤
    │ 99         │ 4            │
    ├────────────┼──────────────┤
    │ 99.9       │ 7            │
    ├────────────┼──────────────┤
    │ 99.99      │ 12           │
    ├────────────┼──────────────┤
    │ 99.999     │ 22           │
    └────────────┴──────────────┘

    434k requests in 60.02s, 155 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    10,000 clients subscribed, 64.01s

    ┌──────────┬─────────┬────────┬─────────┬─────────┬─────────┬─────────┬──────────┐
    │ Stat     │ 2.5%    │ 50%    │ 97.5%   │ 99%     │ Avg     │ Stdev   │ Max      │
    ├──────────┼─────────┼────────┼─────────┼─────────┼─────────┼─────────┼──────────┤
    │ Delivery │ 2.17 ms │ 3.7 ms │ 5.94 ms │ 6.54 ms │ 3.77 ms │ 0.99 ms │ 26.05 ms │
    └──────────┴─────────┴────────┴─────────┴─────────┴─────────┴─────────┴──────────┘
    ┌───────────┬────┬──────┬────────┬────────┬──────────┬─────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%    │ 97.5%  │ Avg      │ Stdev   │ Min │
    ├───────────┼────┼──────┼────────┼────────┼──────────┼─────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 25,989 │ 26,829 │ 25,009.0 │ 4691.65 │ 0   │
    └───────────┴────┴──────┴────────┴────────┴──────────┴─────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    1.56M notifications received in 64.01s (1,559,812 of 1,559,712 expected), 279.3 MB read
    ```

**Broadcast, as many as the servers take**

Calls / second

276

16,562 calls in 60 s, 8 connections

Notifications / second

272,609

16,570,000 received by 1,000 clients

Delivery p50

25.6ms

average 27.9 ms

Delivery p99

63.0ms

max 113 ms

Not delivered

0

0 calls failed

(Server during this run) API Maker **7.8 vCPU** · Redis **0.8 vCPU** · whole server busy **98 %** · load generator busy **38 %**

    autocannon · A broadcast to 1,000 clients, as many as the server takes · server 1 of 4

    ```text
    $ autocannon -c 2 -d 60 -w 2 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections
    2 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
    │ Latency │ 17 ms │ 27 ms │ 40 ms │ 44 ms │ 27.21 ms │ 5.82 ms │ 54 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬───────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev   │ Min   │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┤
    │ Req/Sec   │ 64      │ 65      │ 72      │ 80      │ 71.91   │ 4.11    │ 64    │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼───────┤
    │ Bytes/Sec │ 23.1 kB │ 23.4 kB │ 25.9 kB │ 28.8 kB │ 25.9 kB │ 1.48 kB │ 23 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴───────┘

    Req/Bytes counts sampled once per second.
    # of samples: 120

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 11           │
    ├────────────┼──────────────┤
    │ 0.01       │ 11           │
    ├────────────┼──────────────┤
    │ 0.1        │ 13           │
    ├────────────┼──────────────┤
    │ 1          │ 16           │
    ├────────────┼──────────────┤
    │ 2.5        │ 17           │
    ├────────────┼──────────────┤
    │ 10         │ 20           │
    ├────────────┼──────────────┤
    │ 25         │ 23           │
    ├────────────┼──────────────┤
    │ 50         │ 27           │
    ├────────────┼──────────────┤
    │ 75         │ 31           │
    ├────────────┼──────────────┤
    │ 90         │ 35           │
    ├────────────┼──────────────┤
    │ 97.5       │ 40           │
    ├────────────┼──────────────┤
    │ 99         │ 44           │
    ├────────────┼──────────────┤
    │ 99.9       │ 51           │
    ├────────────┼──────────────┤
    │ 99.99      │ 54           │
    ├────────────┼──────────────┤
    │ 99.999     │ 54           │
    └────────────┴──────────────┘

    4k requests in 60.02s, 1.55 MB read
    ```

    autocannon · A broadcast to 1,000 clients, as many as the server takes · server 2 of 4

    ```text
    $ autocannon -c 2 -d 60 -w 2 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections
    2 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev    │ Max    │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
    │ Latency │ 26 ms │ 48 ms │ 82 ms │ 87 ms │ 49.24 ms │ 14.07 ms │ 105 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
    ┌───────────┬─────────┬─────────┬───────┬───────┬─────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%   │ 97.5% │ Avg     │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼───────┼───────┼─────────┼─────────┼─────────┤
    │ Req/Sec   │ 33      │ 34      │ 39    │ 50    │ 40.12   │ 3.91    │ 33      │
    ├───────────┼─────────┼─────────┼───────┼───────┼─────────┼─────────┼─────────┤
    │ Bytes/Sec │ 11.9 kB │ 12.2 kB │ 14 kB │ 18 kB │ 14.4 kB │ 1.41 kB │ 11.9 kB │
    └───────────┴─────────┴─────────┴───────┴───────┴─────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 120

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 17           │
    ├────────────┼──────────────┤
    │ 0.01       │ 17           │
    ├────────────┼──────────────┤
    │ 0.1        │ 18           │
    ├────────────┼──────────────┤
    │ 1          │ 22           │
    ├────────────┼──────────────┤
    │ 2.5        │ 26           │
    ├────────────┼──────────────┤
    │ 10         │ 32           │
    ├────────────┼──────────────┤
    │ 25         │ 39           │
    ├────────────┼──────────────┤
    │ 50         │ 48           │
    ├────────────┼──────────────┤
    │ 75         │ 58           │
    ├────────────┼──────────────┤
    │ 90         │ 68           │
    ├────────────┼──────────────┤
    │ 97.5       │ 82           │
    ├────────────┼──────────────┤
    │ 99         │ 87           │
    ├────────────┼──────────────┤
    │ 99.9       │ 103          │
    ├────────────┼──────────────┤
    │ 99.99      │ 105          │
    ├────────────┼──────────────┤
    │ 99.999     │ 105          │
    └────────────┴──────────────┘

    2k requests in 60.03s, 867 kB read
    ```

    autocannon · A broadcast to 1,000 clients, as many as the server takes · server 3 of 4

    ```text
    $ autocannon -c 2 -d 60 -w 2 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections
    2 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
    │ Latency │ 16 ms │ 24 ms │ 36 ms │ 38 ms │ 24.39 ms │ 4.96 ms │ 50 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬───────┬─────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5% │ Avg     │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼───────┼─────────┼─────────┼─────────┤
    │ Req/Sec   │ 71      │ 73      │ 80      │ 86    │ 80.09   │ 3.42    │ 71      │
    ├───────────┼─────────┼─────────┼─────────┼───────┼─────────┼─────────┼─────────┤
    │ Bytes/Sec │ 25.6 kB │ 26.3 kB │ 28.8 kB │ 31 kB │ 28.8 kB │ 1.23 kB │ 25.6 kB │
    └───────────┴─────────┴─────────┴─────────┴───────┴─────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 120

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 10           │
    ├────────────┼──────────────┤
    │ 0.01       │ 10           │
    ├────────────┼──────────────┤
    │ 0.1        │ 12           │
    ├────────────┼──────────────┤
    │ 1          │ 15           │
    ├────────────┼──────────────┤
    │ 2.5        │ 16           │
    ├────────────┼──────────────┤
    │ 10         │ 18           │
    ├────────────┼──────────────┤
    │ 25         │ 21           │
    ├────────────┼──────────────┤
    │ 50         │ 24           │
    ├────────────┼──────────────┤
    │ 75         │ 27           │
    ├────────────┼──────────────┤
    │ 90         │ 31           │
    ├────────────┼──────────────┤
    │ 97.5       │ 36           │
    ├────────────┼──────────────┤
    │ 99         │ 38           │
    ├────────────┼──────────────┤
    │ 99.9       │ 46           │
    ├────────────┼──────────────┤
    │ 99.99      │ 50           │
    ├────────────┼──────────────┤
    │ 99.999     │ 50           │
    └────────────┴──────────────┘

    5k requests in 60.03s, 1.73 MB read
    ```

    autocannon · A broadcast to 1,000 clients, as many as the server takes · server 4 of 4

    ```text
    $ autocannon -c 2 -d 60 -w 2 -l -m POST -b '{"name":"announcements","eventData":{"t":<now>,"type":"announcement","text":"Hello from API Maker"}}' -H "x-am-authorization: <token>" -H "x-am-user-authorization: <token>" -H "content-type: application/json" "http://<server>:38246/api/system-api/bench/emit-event-ws"
    Running 60s test @ http://<server>:38246/api/system-api/bench/emit-event-ws
    2 connections
    2 workers

    ┌─────────┬───────┬───────┬───────┬───────┬──────────┬─────────┬───────┐
    │ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev   │ Max   │
    ├─────────┼───────┼───────┼───────┼───────┼──────────┼─────────┼───────┤
    │ Latency │ 15 ms │ 23 ms │ 33 ms │ 36 ms │ 23.25 ms │ 4.55 ms │ 42 ms │
    └─────────┴───────┴───────┴───────┴───────┴──────────┴─────────┴───────┘
    ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
    │ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg     │ Stdev   │ Min     │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Req/Sec   │ 77      │ 77      │ 84      │ 90      │ 83.94   │ 3.03    │ 77      │
    ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
    │ Bytes/Sec │ 27.7 kB │ 27.7 kB │ 30.3 kB │ 32.4 kB │ 30.2 kB │ 1.09 kB │ 27.7 kB │
    └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘

    Req/Bytes counts sampled once per second.
    # of samples: 120

    ┌────────────┬──────────────┐
    │ Percentile │ Latency (ms) │
    ├────────────┼──────────────┤
    │ 0.001      │ 7            │
    ├────────────┼──────────────┤
    │ 0.01       │ 7            │
    ├────────────┼──────────────┤
    │ 0.1        │ 10           │
    ├────────────┼──────────────┤
    │ 1          │ 14           │
    ├────────────┼──────────────┤
    │ 2.5        │ 15           │
    ├────────────┼──────────────┤
    │ 10         │ 18           │
    ├────────────┼──────────────┤
    │ 25         │ 20           │
    ├────────────┼──────────────┤
    │ 50         │ 23           │
    ├────────────┼──────────────┤
    │ 75         │ 26           │
    ├────────────┼──────────────┤
    │ 90         │ 29           │
    ├────────────┼──────────────┤
    │ 97.5       │ 33           │
    ├────────────┼──────────────┤
    │ 99         │ 36           │
    ├────────────┼──────────────┤
    │ 99.9       │ 40           │
    ├────────────┼──────────────┤
    │ 99.99      │ 42           │
    ├────────────┼──────────────┤
    │ 99.999     │ 42           │
    └────────────┴──────────────┘

    5k requests in 60.03s, 1.81 MB read
    ```

    am_ws_load · what the clients received

    ```text
    $ am_ws_load listen "ws://<server>:38246/?x-am-authorization=<token>&x-am-user-authorization=<token>"
    1,000 clients subscribed, 63.78s

    ┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬─────────┬───────────┐
    │ Stat     │ 2.5%     │ 50%      │ 97.5%    │ 99%      │ Avg      │ Stdev   │ Max       │
    ├──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼─────────┼───────────┤
    │ Delivery │ 11.09 ms │ 25.63 ms │ 55.68 ms │ 63.01 ms │ 27.85 ms │ 11.6 ms │ 113.22 ms │
    └──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴─────────┴───────────┘
    ┌───────────┬────┬──────┬─────────┬─────────┬───────────┬──────────┬─────┐
    │ Stat      │ 1% │ 2.5% │ 50%     │ 97.5%   │ Avg       │ Stdev    │ Min │
    ├───────────┼────┼──────┼─────────┼─────────┼───────────┼──────────┼─────┤
    │ Notif/Sec │ 0  │ 0    │ 275,810 │ 286,858 │ 265,211.0 │ 50767.04 │ 0   │
    └───────────┴────┴──────┴─────────┴─────────┴───────────┴──────────┴─────┘

    Delivery : from the moment the request is written to the moment the client reads the notification.
    # of samples: 64

    16.57M notifications received in 63.78s (16,570,000 of 16,562,000 expected), 2542.3 MB read
    ```

**One server stops.** Nobody runs a cluster full : the servers which are left need room for the clients of the one which stops. So the newest clients left first, down to **971,623** : what 3 of the 4 servers hold when each of them is 80 % full. API Maker was then stopped on one of the servers (`systemctl stop api_maker_be`) and stayed down : its clients were closed with `1001`, waited one to five seconds, and connected to the servers which were left.

Clients dropped

242,906

25 % of 971,623

All back after

38.0s

on the 3 servers left

A client was away, p50

14.5s

its own wait of 1 to 5 s counted

A client was away, p99

28.2s

the longest : 31.0 s

They were then told again, each for itself, 1,000 notifications a second for 60 seconds : **all 60,000 arrived**, in 1.33 ms (p50) and 2.45 ms (p99). A client whose subscription had not come back with it would have been told nothing.

## Questions

### How do I scale API Maker WebSockets to N users ?

Add API Maker servers behind a load balancer. Each server holds the clients which reached it (8.5 to 8.8 KB of memory per client), and all of them share one Redis, which carries every notification to the server which holds the client. Count N × 8.5 to 8.8 KB of memory over the servers, and one spare server.

### Should I run one big server or several small ones ?

For the same price they hold about the same number of clients (2,022,026 on 1 × 8 vCPU · 16 GB, 1,915,960 on 2 × 4 vCPU · 8 GB, 1,619,372 on 4 × 2 vCPU · 4 GB) and let in about as many new clients a second. Several servers lose only their share of the clients when one stops (50 % on 2 × 4 vCPU · 8 GB, 25 % on 4 × 2 vCPU · 4 GB) and can be restarted one at a time ; one big server is less to run. Above a few hundred thousand users, several servers.

### Do WebSockets need sticky sessions ?

No. A WebSocket is one long connection : it stays on the server it reached. What is said to it can come from any server, through Redis.

### What limits the number of WebSocket connections ?

Memory : 8.5 to 8.8 KB per client, the kernel and Redis included. The installer sizes the other limits of a server from its memory, so that memory is what ends : the open files of the service and the table of the connections the firewall of Linux tracks, 256 for each MB (with 1,048,576 open files, a server of 16 GB would stop at about a million clients with half of its memory left). Behind a proxy : the ports it reaches one server from (about 64,000 per address) and its own memory for each connection.

### What happens to the clients when a server stops ?

API Maker closes them with the code 1001 (Server is going away). They connect again, to another server when there is one, and subscribe again. Measured on 4 × 2 vCPU · 4 GB : 242,906 clients were all back on the other servers after 38.0 s.
