# Benchmarks

Ta sama praca, ten sam ruch. Poznaj zapisane pomiary, zrozum metodę i powtórz każdy test.

## Co zmierzono

Osiem adapterów, cztery obciążenia i wspólne cele 100 i 1000 żądań/s: 192 pomiary. Każdy pomiar uruchamia nowy proces produkcyjny: sprawdzenie odpowiedzi, 1,5 s bazy, 15 s rozgrzewki, 6 s ustabilizowania, 60 s obciążenia i 30 s powrotu do normy. Zachowano wszystkie trzy powtórzenia. Adaptery mierzono kolejno. Treść udanych odpowiedzi jest sprawdzana przed obciążeniem i po nim; generator żąda do 32 połączeń.

Total5 używa kompaktowego NEWSCHEMA i bezpośredniego kontrolera do walidacji JSON; małe odpowiedzi JSON zwraca bezpośrednio kontroler. Porównanie zawiera pełne zapisane scenariusze, nigdy najlepszy wynik liczbowy. Meteor używa swojego produkcyjnego bundla tylko serwerowego; NestJS używa adaptera Express. Natywne walidatory obejmują mierzoną treść; odrzucanie i konwersje mogą się różnić między frameworkami.

## Środowisko

Współdzielony host Linux x64, Intel Core i7-6700. Każdy kontener pomiarowy był ograniczony do 2 logicznych CPU i 2 GiB, bez sieci zewnętrznej i opublikowanych portów. Generator i symulowana zależność dzieliły kontener. Node 24.14.1 użyto dla Total4, Express, Fastify i Node http; Node 24.15.0 dla Total5, Meteor, AdonisJS i NestJS, zgodnie z runtime bundla Meteor. Wersje runtime są pokazane przy każdym frameworku: różnic nie można przypisać samemu frameworkowi. Usługi produkcyjne pozostały na hoście.

## Czego te wyniki nie dowodzą

To eksperyment ze stałym tempem i zamkniętą pętlą, a nie ranking maksymalnej przepustowości. Osiągnięcie ustawionego celu nie dowodzi, jak adapter radzi sobie z niezależnymi nadejściami czy nasyceniem. Wystąpiło pewne ograniczanie CPU przez limit, odnotowane w przeglądzie. Trzy krótkie powtórzenia nie dowodzą długoterminowej stabilności, braku wycieków pamięci, bezpieczeństwa produkcyjnego, zachowania Flow ani użycia pamięci na Raspberry Pi. Nie wymuszano odśmiecania pamięci. RSS może pozostać zajęte po ustaniu ruchu.

Komórka jest zdrowa, gdy zakończone żądania osiągają co najmniej 95% celu × czas pracy generatora, p99 nie przekracza 250 ms, a liczby błędów, przekroczeń czasu i odpowiedzi innych niż 2xx wynoszą zero. Ten próg nie twierdzi, że wszystkie mają równą maksymalną pojemność.

## Jak czytać wynik

Porównuj to samo obciążenie przy tym samym tempie docelowym i czytaj razem opóźnienie, CPU, pamięć, błędy i pokrycie celu. Ważna jest też wersja runtime. Te pomiary nie dowodzą, że jeden framework zawsze zużywa mniej zasobów. Total.js 4 i 5 pokazano osobno; każdy używa zapisanej implementacji i runtime.

## Pełne porównanie frameworków

Zakończono: 2026-10-18T13:56:39.143Z; Node v24.14.1 / v24.15.0 (see runtimeByFramework).

| Framework | Node | Workload | req/s | Healthy | RSS baseline MiB | RSS load MiB | RSS recovery MiB | CPU % | p99 ms |
|---|---|---|---:|---|---|---|---|---|---|
| Total.js 4 | v24.14.1 | hello | 100 | 3/3 | 61.2 [61.0–61.2] | 89.8 [87.0–90.7] | 91.0 [88.3–105.4] | 1.7 [1.7–1.7] | 5.0 [5.0–6.0] |
| Express | v24.14.1 | hello | 100 | 3/3 | 74.2 [74.1–74.3] | 90.7 [90.4–91.5] | 90.8 [90.3–91.5] | 1.9 [1.9–2.0] | 7.0 [6.0–7.0] |
| Fastify | v24.14.1 | hello | 100 | 3/3 | 76.0 [75.5–76.0] | 91.3 [91.0–91.9] | 91.4 [91.0–91.9] | 1.4 [1.4–1.4] | 5.0 [5.0–5.0] |
| Node.js http | v24.14.1 | hello | 100 | 3/3 | 50.2 [50.2–50.3] | 68.8 [66.6–69.2] | 69.2 [67.0–69.5] | 1.4 [1.4–1.4] | 5.0 [5.0–5.0] |
| Total.js 4 | v24.14.1 | catalog | 100 | 3/3 | 61.3 [61.1–62.1] | 104.6 [94.9–106.2] | 106.4 [105.1–108.6] | 2.1 [2.1–2.1] | 8.0 [8.0–8.0] |
| Express | v24.14.1 | catalog | 100 | 3/3 | 74.1 [74.0–74.1] | 92.0 [91.9–94.5] | 92.3 [91.9–94.5] | 2.3 [2.3–2.4] | 9.0 [9.0–9.0] |
| Fastify | v24.14.1 | catalog | 100 | 3/3 | 75.8 [75.2–75.8] | 93.2 [92.6–93.4] | 93.4 [93.1–93.5] | 1.9 [1.8–1.9] | 8.0 [7.0–8.0] |
| Node.js http | v24.14.1 | catalog | 100 | 3/3 | 50.2 [50.1–50.3] | 66.0 [65.9–68.4] | 66.3 [66.1–68.7] | 1.8 [1.8–1.8] | 6.0 [6.0–7.0] |
| Total.js 4 | v24.14.1 | validate | 100 | 3/3 | 61.4 [61.3–61.6] | 96.4 [95.4–100.2] | 100.8 [98.3–101.9] | 2.0 [2.0–2.2] | 7.0 [6.0–8.0] |
| Express | v24.14.1 | validate | 100 | 3/3 | 74.0 [74.0–75.0] | 98.5 [94.4–99.0] | 98.6 [94.4–99.3] | 2.3 [2.2–2.3] | 9.0 [8.0–9.0] |
| Fastify | v24.14.1 | validate | 100 | 3/3 | 75.7 [75.6–76.0] | 97.3 [96.6–98.0] | 97.7 [96.2–98.0] | 1.7 [1.6–1.7] | 6.0 [5.0–6.0] |
| Node.js http | v24.14.1 | validate | 100 | 3/3 | 50.3 [50.2–50.5] | 71.6 [71.4–72.2] | 71.8 [71.4–72.6] | 1.7 [1.7–1.7] | 6.0 [6.0–6.0] |
| Total.js 4 | v24.14.1 | upstream | 100 | 3/3 | 67.2 [66.8–67.9] | 167.8 [166.7–169.5] | 175.3 [169.6–176.7] | 5.7 [5.7–5.8] | 19.0 [19.0–19.0] |
| Express | v24.14.1 | upstream | 100 | 3/3 | 80.2 [79.8–80.2] | 171.3 [171.2–171.4] | 173.7 [172.9–173.7] | 6.0 [5.7–6.2] | 20.0 [19.0–20.0] |
| Fastify | v24.14.1 | upstream | 100 | 3/3 | 80.3 [80.1–80.7] | 165.9 [165.8–168.4] | 168.7 [168.3–173.1] | 5.6 [4.8–5.8] | 20.0 [19.0–20.0] |
| Node.js http | v24.14.1 | upstream | 100 | 3/3 | 60.8 [60.7–61.6] | 161.9 [158.4–172.1] | 164.2 [159.9–174.2] | 5.5 [5.2–5.5] | 18.0 [18.0–19.0] |
| Total.js 4 | v24.14.1 | hello | 1000 | 3/3 | 61.0 [60.9–61.1] | 159.3 [150.1–167.0] | 174.3 [172.9–174.5] | 7.9 [7.8–8.2] | 5.0 [5.0–5.0] |
| Express | v24.14.1 | hello | 1000 | 3/3 | 74.1 [73.9–74.2] | 90.8 [90.4–91.5] | 90.9 [90.5–91.6] | 7.3 [7.1–7.6] | 5.0 [4.0–5.0] |
| Fastify | v24.14.1 | hello | 1000 | 3/3 | 75.9 [75.4–76.8] | 91.2 [91.0–91.6] | 91.2 [91.0–91.6] | 4.9 [4.9–5.0] | 3.0 [3.0–3.0] |
| Node.js http | v24.14.1 | hello | 1000 | 3/3 | 50.2 [50.2–50.2] | 67.9 [67.5–69.8] | 67.9 [67.7–70.0] | 4.4 [4.4–4.5] | 3.0 [3.0–3.0] |
| Total.js 4 | v24.14.1 | catalog | 1000 | 3/3 | 61.2 [61.0–61.3] | 179.5 [179.5–180.0] | 179.9 [179.4–180.2] | 9.9 [9.9–9.9] | 13.0 [6.0–18.0] |
| Express | v24.14.1 | catalog | 1000 | 3/3 | 73.8 [73.7–74.0] | 91.8 [91.1–92.9] | 91.8 [91.3–92.9] | 9.5 [9.4–9.8] | 5.0 [5.0–11.0] |
| Fastify | v24.14.1 | catalog | 1000 | 3/3 | 75.7 [75.3–75.9] | 94.1 [93.8–94.2] | 94.1 [93.8–94.2] | 7.1 [7.1–7.1] | 5.0 [5.0–5.0] |
| Node.js http | v24.14.1 | catalog | 1000 | 3/3 | 50.2 [50.1–50.2] | 72.6 [71.2–72.9] | 72.6 [71.2–73.2] | 7.3 [7.2–7.4] | 5.0 [4.0–5.0] |
| Total.js 4 | v24.14.1 | validate | 1000 | 3/3 | 62.2 [61.6–62.5] | 171.9 [170.7–172.7] | 175.7 [175.3–176.6] | 9.7 [9.5–10.0] | 6.0 [6.0–6.0] |
| Express | v24.14.1 | validate | 1000 | 3/3 | 74.4 [74.2–74.6] | 98.8 [98.2–99.7] | 98.8 [98.2–99.7] | 8.9 [8.9–9.2] | 8.0 [6.0–21.0] |
| Fastify | v24.14.1 | validate | 1000 | 3/3 | 75.9 [75.7–76.4] | 98.1 [98.1–98.4] | 98.1 [98.1–98.5] | 6.3 [6.2–6.3] | 5.0 [4.0–12.0] |
| Node.js http | v24.14.1 | validate | 1000 | 3/3 | 50.2 [50.2–50.4] | 71.0 [70.4–72.6] | 74.9 [74.2–76.4] | 6.2 [6.0–6.3] | 4.0 [4.0–13.0] |
| Total.js 4 | v24.14.1 | upstream | 1000 | 3/3 | 67.8 [67.8–67.8] | 202.3 [201.4–204.1] | 203.0 [201.6–204.7] | 36.3 [34.7–36.6] | 16.0 [15.0–16.0] |
| Express | v24.14.1 | upstream | 1000 | 3/3 | 80.7 [79.7–80.9] | 178.7 [177.6–187.7] | 182.6 [181.9–190.4] | 35.0 [32.6–35.4] | 15.0 [15.0–16.0] |
| Fastify | v24.14.1 | upstream | 1000 | 3/3 | 79.3 [79.3–79.3] | 194.0 [179.4–194.6] | 194.0 [179.6–194.9] | 33.8 [27.7–34.2] | 15.0 [14.0–15.0] |
| Node.js http | v24.14.1 | upstream | 1000 | 3/3 | 60.9 [60.7–61.0] | 171.9 [171.8–174.6] | 178.0 [175.5–179.3] | 29.0 [23.6–30.5] | 14.0 [13.0–15.0] |
| Meteor | v24.15.0 | hello | 100 | 3/3 | 123.7 [123.5–124.7] | 130.2 [128.1–131.3] | 159.1 [151.6–160.9] | 3.5 [3.5–3.6] | 15.0 [14.0–19.0] |
| Meteor | v24.15.0 | catalog | 100 | 3/3 | 124.7 [123.3–124.8] | 138.9 [138.8–139.4] | 162.5 [157.0–162.7] | 3.9 [3.9–4.0] | 15.0 [14.0–16.0] |
| Meteor | v24.15.0 | validate | 100 | 3/3 | 124.4 [123.2–124.6] | 137.0 [134.6–138.8] | 163.4 [161.2–169.2] | 3.9 [3.8–3.9] | 18.0 [15.0–22.0] |
| Meteor | v24.15.0 | upstream | 100 | 3/3 | 126.5 [126.2–127.6] | 187.0 [181.6–188.3] | 188.9 [184.5–191.2] | 8.0 [7.7–8.1] | 25.0 [24.0–25.0] |
| Meteor | v24.15.0 | hello | 1000 | 3/3 | 124.3 [123.4–125.5] | 168.6 [167.6–171.1] | 169.0 [168.5–172.3] | 12.8 [12.7–12.8] | 10.0 [8.0–18.0] |
| Meteor | v24.15.0 | catalog | 1000 | 3/3 | 124.1 [123.3–124.2] | 167.6 [167.6–172.5] | 168.0 [167.7–173.2] | 15.2 [15.1–15.9] | 10.0 [9.0–10.0] |
| Meteor | v24.15.0 | validate | 1000 | 3/3 | 125.2 [124.6–126.1] | 174.9 [173.8–175.0] | 176.3 [175.0–176.6] | 14.8 [14.6–14.9] | 10.0 [9.0–13.0] |
| Meteor | v24.15.0 | upstream | 1000 | 3/3 | 127.8 [127.2–128.3] | 213.9 [213.8–217.2] | 124.5 [122.1–126.7] | 38.2 [36.8–41.4] | 18.0 [17.0–19.0] |
| AdonisJS | v24.15.0 | hello | 100 | 3/3 | 114.9 [113.9–115.3] | 143.4 [143.0–149.2] | 144.3 [143.1–149.4] | 2.5 [2.3–2.5] | 9.0 [9.0–10.0] |
| AdonisJS | v24.15.0 | catalog | 100 | 3/3 | 114.4 [113.7–116.0] | 142.7 [142.7–142.9] | 143.6 [142.9–144.3] | 3.0 [3.0–3.1] | 13.0 [12.0–13.0] |
| AdonisJS | v24.15.0 | validate | 100 | 3/3 | 114.5 [114.3–115.0] | 147.0 [146.6–147.4] | 148.5 [148.1–148.5] | 3.0 [2.9–3.0] | 12.0 [12.0–13.0] |
| AdonisJS | v24.15.0 | upstream | 100 | 3/3 | 115.9 [112.8–116.2] | 195.2 [194.7–198.7] | 197.2 [194.8–199.7] | 6.3 [6.1–6.3] | 20.0 [20.0–21.0] |
| AdonisJS | v24.15.0 | hello | 1000 | 3/3 | 114.3 [113.6–115.4] | 145.3 [144.6–149.7] | 145.3 [144.6–149.6] | 10.7 [10.4–10.7] | 6.0 [6.0–7.0] |
| AdonisJS | v24.15.0 | catalog | 1000 | 3/3 | 113.7 [113.2–114.4] | 149.3 [149.2–151.7] | 151.8 [151.7–153.0] | 14.5 [14.4–14.7] | 9.0 [8.0–9.0] |
| AdonisJS | v24.15.0 | validate | 1000 | 3/3 | 115.2 [115.1–115.7] | 149.4 [149.0–149.8] | 149.4 [148.9–149.5] | 13.7 [13.6–14.3] | 9.0 [7.0–10.0] |
| AdonisJS | v24.15.0 | upstream | 1000 | 3/3 | 115.0 [114.8–115.5] | 208.4 [203.9–221.8] | 212.1 [206.0–223.5] | 37.8 [35.6–38.7] | 15.0 [15.0–17.0] |
| NestJS · Express | v24.15.0 | hello | 100 | 3/3 | 99.8 [99.7–100.9] | 126.2 [125.2–130.1] | 126.4 [125.2–130.1] | 2.1 [2.1–2.2] | 7.0 [7.0–8.0] |
| NestJS · Express | v24.15.0 | catalog | 100 | 3/3 | 100.3 [99.8–100.4] | 127.1 [127.0–127.7] | 127.3 [127.0–127.8] | 2.5 [2.5–2.6] | 10.0 [10.0–10.0] |
| NestJS · Express | v24.15.0 | validate | 100 | 3/3 | 100.4 [100.3–101.0] | 130.0 [129.3–130.4] | 130.5 [130.5–130.9] | 2.4 [2.3–2.4] | 9.0 [8.0–13.0] |
| NestJS · Express | v24.15.0 | upstream | 100 | 3/3 | 102.4 [101.9–102.9] | 188.1 [183.4–189.5] | 190.1 [185.1–192.4] | 6.2 [6.1–6.2] | 20.0 [20.0–22.0] |
| NestJS · Express | v24.15.0 | hello | 1000 | 3/3 | 100.4 [99.3–101.3] | 129.6 [129.4–130.0] | 129.8 [129.4–130.2] | 8.5 [8.5–8.6] | 5.0 [5.0–13.0] |
| NestJS · Express | v24.15.0 | catalog | 1000 | 3/3 | 100.8 [100.3–101.1] | 129.2 [127.9–132.9] | 129.4 [129.2–132.9] | 11.4 [11.3–11.5] | 11.0 [8.0–11.0] |
| NestJS · Express | v24.15.0 | validate | 1000 | 3/3 | 101.3 [101.2–101.4] | 132.2 [131.7–132.7] | 132.2 [131.7–132.7] | 10.7 [10.7–11.0] | 7.0 [6.0–8.0] |
| NestJS · Express | v24.15.0 | upstream | 1000 | 3/3 | 103.0 [101.1–103.4] | 201.2 [201.0–201.7] | 201.2 [201.1–201.7] | 37.1 [31.8–38.3] | 16.0 [16.0–17.0] |
| Total.js 5 | v24.15.0 | hello | 100 | 3/3 | 63.1 [63.0–63.2] | 94.6 [93.9–95.2] | 103.2 [103.1–104.0] | 1.6 [1.5–1.6] | 5.0 [5.0–6.0] |
| Total.js 5 | v24.15.0 | catalog | 100 | 3/3 | 63.3 [63.3–63.5] | 99.9 [99.9–100.7] | 107.5 [107.2–108.8] | 2.0 [1.9–2.1] | 7.0 [6.0–8.0] |
| Total.js 5 | v24.15.0 | validate | 100 | 3/3 | 63.2 [63.2–63.2] | 93.4 [92.2–94.2] | 96.7 [94.7–101.4] | 1.9 [1.8–2.0] | 7.0 [6.0–7.0] |
| Total.js 5 | v24.15.0 | upstream | 100 | 3/3 | 69.5 [69.4–69.5] | 168.3 [166.0–169.2] | 169.8 [167.4–172.5] | 5.6 [5.4–5.6] | 18.0 [18.0–18.0] |
| Total.js 5 | v24.15.0 | hello | 1000 | 3/3 | 62.8 [62.8–63.2] | 165.7 [164.9–166.7] | 173.8 [173.1–174.3] | 8.2 [8.1–8.2] | 6.0 [6.0–6.0] |
| Total.js 5 | v24.15.0 | catalog | 1000 | 3/3 | 63.3 [63.3–63.5] | 175.0 [173.3–175.6] | 175.5 [173.7–181.0] | 9.9 [9.9–9.9] | 6.0 [5.0–9.0] |
| Total.js 5 | v24.15.0 | validate | 1000 | 3/3 | 63.2 [63.0–63.5] | 169.2 [164.2–169.4] | 171.4 [170.9–171.4] | 9.1 [9.0–9.2] | 22.0 [6.0–27.0] |
| Total.js 5 | v24.15.0 | upstream | 1000 | 3/3 | 68.4 [68.1–69.2] | 205.0 [203.3–206.0] | 207.9 [203.8–210.7] | 36.4 [30.2–36.8] | 23.0 [22.0–24.0] |

[Pomiary surowe](/benchmarks/linux-20261017/general.json)

[Zamrożone źródła i blokady zależności](/benchmarks/linux-20261017/sources.tar.gz)

[Zapisany raport](/benchmarks/linux-20261017/general-report.md)

[CSV według scenariusza](/benchmarks/linux-20261017/general.csv)

## Odtwórz i sprawdź

Użyj pustego katalogu z Dockerem (kontenery Linux), curl i tar. Node.js nie jest potrzebny na hoście: sprawdzenie sumy kontrolnej i zestaw testów używają Node 24.15.0 w Dockerze. Pierwsze budowanie pobiera zależności i kompiluje Meteor, co może potrwać kilka minut. Przygotowanie wymaga internetu; kontenery testowe nie mają sieci zewnętrznej. Każdy mierzony scenariusz trwa około sześciu minut.

Pełny zestaw uruchamia wszystkie osiem adapterów na Node 24.15.0 w kontenerach Linux. Zawiera program uruchamiający, adaptery, blokady zależności i instrukcje budowania Meteor. Opublikowane pomiary zachowują oryginalne wersje runtime i oryginalne archiwum źródeł, dostępne w dowodach; ten zestaw ujednolica tylko nowe uruchomienia.

[Pobierz pełny zestaw testowy](https://forge.totaljs.es/benchmarks/node-24.15.0/sources.tar.gz)

1. Pobierz i przygotuj. Odnośnik zawiera program uruchamiający, adaptery i blokady zależności; nie trzeba instalować Forge ani klonować repozytorium. W pustym katalogu uruchom poniższe polecenia. Jeśli pobrano przyciskiem, zachowaj nazwę sources.tar.gz i pomiń curl.

```bash
curl --fail --location --output sources.tar.gz 'https://forge.totaljs.es/benchmarks/node-24.15.0/sources.tar.gz' &&
docker run --rm --platform linux/amd64 --network none -v "$PWD:/kit:ro" node:24.15.0-bookworm node -e 'const fs=require("node:fs"),crypto=require("node:crypto");if(crypto.createHash("sha256").update(fs.readFileSync("/kit/sources.tar.gz")).digest("hex")!=="65801cd865a3fc961e69ba8df421ed198acdc399d29934714fb954e4de1db651")throw Error("SHA-256 mismatch");' &&
tar -xzf sources.tar.gz &&
docker build --platform linux/amd64 -t forge-benchmark-local . &&
mkdir -p results
```

2. Sprawdź instalację (około 15–30 sekund). Ten krótki test tworzy smoke.json i weryfikuje jego zapisane dane wejściowe; nie jest to wynik wydajności do publikacji.

```bash
docker run --rm --platform linux/amd64 --cpus 2 --memory 2g --memory-swap 2g --pids-limit 256 --read-only --network none --user "$(id -u):$(id -g)" --tmpfs /tmp:rw,nosuid,nodev,size=512m,mode=1777 -v "$PWD/results:/results" forge-benchmark-local node benchmarks/v2/run.cjs --smoke --frameworks totaljs --workloads hello --rates 1000 --out /results/smoke.json
docker run --rm --platform linux/amd64 --cpus 2 --memory 2g --memory-swap 2g --pids-limit 256 --read-only --network none --user "$(id -u):$(id -g)" --tmpfs /tmp:rw,nosuid,nodev,size=512m,mode=1777 -v "$PWD/results:/results" forge-benchmark-local node benchmarks/v2/verify.cjs /results/smoke.json --allow-smoke
```

3. Uruchom i zweryfikuj wybrany pomiar. Wyniki są zapisywane w results/my-run.json w wybranym katalogu benchmarks. Program odmawia nadpisania istniejącego wyniku: do powtórzenia użyj innej nazwy pliku. Weryfikacja sprawdza kompletność i dane wejściowe, nie zgodność z opublikowanymi liczbami.

```bash
docker run --rm --platform linux/amd64 --cpus 2 --memory 2g --memory-swap 2g --pids-limit 256 --read-only --network none --user "$(id -u):$(id -g)" --tmpfs /tmp:rw,nosuid,nodev,size=512m,mode=1777 -v "$PWD/results:/results" forge-benchmark-local node benchmarks/v2/run.cjs --frameworks totaljs --workloads hello --rates 1000 --seconds 60 --warmup 15 --rest 30 --reps 3 --connections 32 --out /results/my-run.json
docker run --rm --platform linux/amd64 --cpus 2 --memory 2g --memory-swap 2g --pids-limit 256 --read-only --network none --user "$(id -u):$(id -g)" --tmpfs /tmp:rw,nosuid,nodev,size=512m,mode=1777 -v "$PWD/results:/results" forge-benchmark-local node benchmarks/v2/verify.cjs /results/my-run.json
```

[JSON](/benchmarks/summary.json) · [Przegląd integralności i środowiska](/benchmarks/linux-20261017/review.json) · [SHA-256](/benchmarks/linux-20261017/SHA256SUMS.txt)
