Сравнение производительности
JSON: обновлён 2026-10-04. Один рабочий процесс приложения и восемь потоков выполнения.
Замеры базы данных: PostgreSQL — выборка 20 строк из 1 000 000 записей. PostgreSQL и статика используют отдельные конфигурации, описанные в соответствующих разделах.
Обработка JSON
Серия девяти фреймворков — 2026-10-03, cwfr обновлён 2026-10-04
Обработчик POST /count получает ровно 1 048 576 байт (1 МиБ) UTF-8 JSON, полностью разбирает документ и возвращает {"count":4097}. В объекте есть вложенные объекты/массивы, Unicode, экранированные строки и разные типы значений. Считаются ключи первого уровня; результат и дерево JSON между запросами не кешируются.
Характеристики ПК
Intel Core i7-12700F, Linux host network.
Приложения и nginx:
- CPU 0–7 (четыре физических P-ядра с SMT),
- 2 ГиБ на контейнер приложения
- nofile 65536
wrk:
- восемь потоков на CPU 8–15
Общий nginx имеет два воркера и один upstream-адрес на приложение, ограничивает тело 2 МиБ, не буферизует тело и не кеширует ответы.
TLS, сжатие, access log и БД отключены.
cwfr держит тело запроса в памяти.
Rails — ActionController::Metal.
Laravel использует разобранный JSON запроса и проход json_validate.
facil.io применяет native FIOBJ JSON;
Kore держит запроса тело в памяти и полностью строит дерево Jansson в фоновой задаче.
90 замеров в одной серии: девять фреймворков, два уровня конкурентности и пять повторов.
Всё сравнение повторено со сбором RSS: первичный прогрев 30 с, перед каждым замером 5 с, пять повторов по 15 с при 16/64 keep-alive соединениях, порядок перемешан с seed 20261003.
16 соединений
| Фреймворк | req/s | min–max req/s | p50, мс | p95, мс | p99, мс | CPU приложения/запрос, мкс | CPU прокси/запрос, мкс | RSS медиана, МиБ |
|---|---|---|---|---|---|---|---|---|
| cwfr (C) | 1 997 | 1 835–2 055 | 7,85 | 11,28 | 13,01 | 3 211 | 449 | 60,82 |
| Spring Boot (Java) | 1 723 | 1 721–1 759 | 8,97 | 12,24 | 14,40 | 4 107 | 381 | 586,71 |
| Laravel (PHP) | 840 | 758–874 | 18,86 | 22,57 | 29,93 | 9 023 | 446 | 293,07 |
| facil.io (C) | 734 | 474–862 | 16,35 | 1 120,07 | 1 637,76 | 6 414 | 378 | 34,00 |
| Fiber (Go) | 638 | 568–657 | 23,14 | 46,09 | 61,49 | 11 632 | 374 | 82,55 |
| Fastify (JavaScript) | 618 | 593–626 | 22,55 | 62,03 | 91,59 | 11 682 | 420 | 490,80 |
| Ruby on Rails (Ruby) | 283 | 196–286 | 54,03 | 69,68 | 94,19 | 4 108 | 318 | 226,82 |
| Kore + Jansson (C) | 217 | 177–218 | 73,24 | 91,56 | 104,44 | 20 635 | 314 | 34,18 |
| Django (Python) | 194 | 179–197 | 81,26 | 102,92 | 114,28 | 5 523 | 306 | 86,62 |
64 соединений
| Фреймворк | req/s | min–max req/s | p50, мс | p95, мс | p99, мс | CPU приложения/запрос, мкс | CPU прокси/запрос, мкс | RSS медиана, МиБ |
|---|---|---|---|---|---|---|---|---|
| cwfr (C) | 1 908 | 1 809–1 978 | 33,40 | 39,58 | 46,13 | 3 352 | 470 | 84,82 |
| Spring Boot (Java) | 1 727 | 1 397–1 778 | 37,46 | 41,31 | 43,92 | 4 124 | 379 | 579,70 |
| facil.io (C) | 828 | 626–925 | 68,22 | 1 157,88 | 1 896,61 | 6 802 | 378 | 37,80 |
| Laravel (PHP) | 823 | 680–865 | 76,68 | 83,70 | 112,99 | 9 082 | 474 | 315,58 |
| Fiber (Go) | 679 | 652–683 | 75,31 | 325,90 | 493,56 | 11 145 | 381 | 200,59 |
| Fastify (JavaScript) | 595 | 475–627 | 91,26 | 314,57 | 568,00 | 12 648 | 417 | 540,44 |
| Ruby on Rails (Ruby) | 267 | 189–271 | 236,56 | 274,93 | 295,04 | 4 350 | 315 | 241,94 |
| Kore + Jansson (C) | 210 | 186–217 | 295,67 | 388,88 | 448,16 | 21 976 | 320 | 73,18 |
| Django (Python) | 179 | 130–183 | 347,78 | 374,67 | 517,21 | 6 000 | 327 | 88,33 |
В этой серии срабатывал общий лимит памяти cgroup: facil.io (C): memory.events max=165877, oom=0, oom_kill=0. Reclaim мог влиять на задержки; его точный вклад отдельно не выделен. Эти счётчики не характеризуют RSS процесса.
Память и ограничения замеров
RSS — сумма VmRSS всех процессов приложения в контейнере, включая управляющие процессы; потоки отдельно не суммируются. Выборки снимаются каждые 200 мс во время измеряемой нагрузки. В таблице медиана медиан RSS пяти повторов, в МиБ (1 048 576 байт).
Измеренные версии
- cwfr (C): 5da69b013eec43a06f9cb61f4e2c681fadeb3f9e; Release; 1 × (1 event worker + 8 handler threads)
- Fastify (JavaScript): v24.21.0; Fastify 5.6.2; 1 × 8 Worker Threads; V8 old/young heap limits 64/8 MiB per thread
- Django (Python): Python 3.13.16; Django 5.2.7; Gunicorn 23.0.0; 1 × 8 gthread
- Spring Boot (Java): Spring Boot 3.5.7; openjdk version "21.0.12.1" 2026-08-18 LTS; 1 × 8 Tomcat threads
- Fiber (Go): go1.25.14; Fiber 3.0.0; encoding/json; 1 × GOMAXPROCS=8
- Ruby on Rails (Ruby): Ruby 3.4.11; Rails 8.0.2; Puma 6.6.1; 1 × 8 threads
- Laravel (PHP): PHP 8.4.26 ZTS; Laravel 12.69.3; Octane v2.20.0; FrankenPHP v1.12.7 PHP 8.4.26 Caddy v2.11.4 h1:XKxkMTgNSizEvKG6QHue6cAsFOteU2qA61w2tKkCWi0=; 1 × 8 PHP worker threads; cached request JSON + json_validate
- facil.io (C): facil.io 0.7.6; 512a354dbd31e1895647df852d1565f9d408ed91; native FIOBJ JSON; 1 process + 8 reactor/handler threads
- Kore + Jansson (C): Kore 4.3.0; source SHA256 94f767eb113f2c97a133b9609c78c4e3795c420dc8726154edce49965df6b8ed; Jansson 2.14-2; 1 worker + 8 task threads
- gateway: nginx version: nginx/1.28.0; 2 workers
PostgreSQL: выборка raw SQL
Дата серии: 2026-10-04.
Ядро CWFR: 5da69b013eec43a06f9cb61f4e2c681fadeb3f9e. main.body_store: mode: "auto", file_threshold: 5000000 байт. Маленькое тело POST остаётся в памяти; лимит тела — 2097152 байт.
Запрос POST /db принимает {"category":42,"after":1000} и возвращает двадцать упорядоченных строк с полями id, category, name, price_cents и active.
Отдельный PostgreSQL 17.6 содержит 1 000 000 синтетических записей, составной B-tree индекс по (category, id).
Оба значения передаются через bind-параметры драйвера. ORM, кеш ответа приложения, TLS и PgBouncer не используются.
Исполнение SQL, чтение всех двадцати строк, преобразование типов и сериализация JSON входят в измерение.
SELECT id, category, name, price_cents, active
FROM bench_items
WHERE category = $1::integer AND id > $2::integer
ORDER BY id
LIMIT 20;Запрос и набор выбираемых полей эквивалентны во всех приложениях.
Синтаксис placeholder адаптирован к драйверу.
Восемь потоков клиента используют восемь разных фиксированных пар параметров с диапазонами по всей таблице, одна пара на поток.
Каждый ответ сравнивается с полным ожидаемым документом из двадцати строк для этого потока.
Пустая выборка и неверные параметры проверены на прямом порту приложения и через прокси.
PostgreSQL · 16 соединений
| Фреймворк | req/s | min–max req/s | p99, мс | CPU приложения/запрос, мкс | CPU БД/запрос, мкс | App anon медиана, МиБ | App working set пик, МиБ | RSS приложения медиана, МиБ |
|---|---|---|---|---|---|---|---|---|
| Fiber (Go) | 52 763 | 50 348–54 180 | 0,82 | 53 | 105 | 7,5 | 19,2 | 17,32 |
| facil.io (C) | 48 180 | 47 251–48 524 | 0,68 | 63 | 100 | 16,3 | 19,2 | 23,32 |
| cwfr (C) | 46 070 | 43 551–49 423 | 2,27 | 72 | 106 | 11,5 | 16,2 | 23,09 |
| Kore + Jansson (C) | 41 388 | 38 724–41 659 | 0,89 | 87 | 99 | 7,6 | 15,1 | 19,21 |
| Spring Boot (Java) | 40 291 | 38 462–44 875 | 1,58 | 87 | 109 | 373,5 | 416,3 | 396,48 |
| Fastify (JavaScript) | 31 829 | 28 445–33 259 | 2,07 | 144 | 94 | 356,6 | 373,3 | 405,11 |
| Laravel (PHP) | 5 884 | 5 835–5 960 | 4,40 | 1 193 | 130 | 357,0 | 577,2 | 453,18 |
| Django (Python) | 2 488 | 2 365–2 497 | 9,36 | 462 | 78 | 45,2 | 68,2 | 72,71 |
| Ruby on Rails (Ruby) | 1 952 | 1 735–2 089 | 57,46 | 606 | 104 | 63,9 | 106,4 | 78,84 |
PostgreSQL · 64 соединений
| Фреймворк | req/s | min–max req/s | p99, мс | CPU приложения/запрос, мкс | CPU БД/запрос, мкс | App anon медиана, МиБ | App working set пик, МиБ | RSS приложения медиана, МиБ |
|---|---|---|---|---|---|---|---|---|
| Fiber (Go) | 48 916 | 48 244–49 243 | 1,94 | 57 | 112 | 7,8 | 19,9 | 17,50 |
| cwfr (C) | 47 929 | 47 218–48 603 | 3,18 | 69 | 109 | 11,5 | 16,4 | 23,08 |
| facil.io (C) | 44 055 | 41 626–46 317 | 2,40 | 65 | 111 | 16,1 | 19,3 | 23,21 |
| Spring Boot (Java) | 43 115 | 37 807–43 117 | 2,26 | 82 | 109 | 372,7 | 416,0 | 395,71 |
| Kore + Jansson (C) | 38 835 | 37 157–41 290 | 3,25 | 89 | 111 | 8,0 | 15,4 | 19,58 |
| Fastify (JavaScript) | 34 098 | 30 049–36 747 | 6,03 | 161 | 108 | 354,2 | 373,6 | 402,64 |
| Laravel (PHP) | 5 561 | 5 105–5 844 | 14,90 | 1 245 | 158 | 482,7 | 670,6 | 578,88 |
| Django (Python) | 2 497 | 2 406–2 503 | 30,04 | 462 | 79 | 45,2 | 68,5 | 72,77 |
| Ruby on Rails (Ruby) | 1 965 | 1 862–2 060 | 302,08 | 612 | 109 | 61,7 | 103,6 | 76,59 |
Память до и после нагрузки
Сохранены idle-снимки перед явным прогревом и после прогрева всех фреймворков, а также снимки до/после каждого прогона.
Память БД включает сервер и idle-соединения всех фреймворков.
В raw data отдельно для приложения, БД и прокси есть медианы и пики current/anon/working set; RSS каждого PID и суммы по контейнерам сохранены отдельно.
| Контейнер | Idle до прогрева, МиБ | После прогрева, МиБ | После последнего прогона, МиБ | Пик под нагрузкой, МиБ |
|---|---|---|---|---|
| cwfr (C) | 12,9 | 12,9 | 15,7 | 16,4 |
| Fastify (JavaScript) | 370,5 | 256,2 | 372,7 | 373,6 |
| Django (Python) | 65,9 | 66,0 | 67,8 | 68,5 |
| Spring Boot (Java) | 388,3 | 412,4 | 397,9 | 416,3 |
| Fiber (Go) | 16,8 | 16,9 | 18,3 | 19,9 |
| Ruby on Rails (Ruby) | 99,0 | 100,4 | 87,0 | 106,4 |
| Laravel (PHP) | 235,8 | 331,0 | 671,2 | 670,6 |
| facil.io (C) | 15,4 | 15,4 | 18,4 | 19,3 |
| Kore + Jansson (C) | 16,1 | 12,6 | 13,9 | 15,4 |
| postgres | 208,8 | 209,7 | 209,6 | 217,4 |
| gateway | 9,6 | 10,0 | 11,7 | 14,1 |
Измеренные версии PostgreSQL-набора
- cwfr: {"core_source": "5da69b013eec43a06f9cb61f4e2c681fadeb3f9e", "libpq": "libpq5:amd64\t18.6-0ubuntu0.26.04.1"}
- fastify:
- django: 3.13.16 5.2.7 3.2.13
- spring: openjdk version "21.0.12.1" 2026-08-18 LTS OpenJDK Runtime Environment Temurin-21.0.12.1+1 (build 21.0.12.1+1-LTS) OpenJDK 64-Bit Server VM Temurin-21.0.12.1+1 (build 21.0.12.1+1-LTS, mixed mode, sharing)
- fiber:
- rails: 3.4.11; 8.0.2; 1.6.2; 6.6.1
- laravel: PHP 8.4.26; Laravel 12.69.3; Octane v2.20.0; pdo_pgsql
PDO Driver for PostgreSQL => enabled PostgreSQL(libpq) Version => 15.19
- facil: facil.io 0.7.6; 512a354dbd31e1895647df852d1565f9d408ed91; libpq/Jansson; 1 process + 8 reactor/handler threads; libjansson4:amd64 2.14-2 libpq5:amd64 15.19-0+deb12u1
- kore: Kore 4.3.0; SHA256 94f767eb113f2c97a133b9609c78c4e3795c420dc8726154edce49965df6b8ed; libpq/Jansson; 1 worker + 8 task threads; libjansson4:amd64 2.14-2 libpq5:amd64 15.19-0+deb12u1
- postgres: postgres (PostgreSQL) 17.6 (Debian 17.6-2.pgdg12+1)
- gateway: nginx version: nginx/1.28.0
- spring_jars: ["BOOT-INF/lib/spring-boot-3.5.7.jar", "BOOT-INF/lib/spring-boot-autoconfigure-3.5.7.jar", "BOOT-INF/lib/HikariCP-6.3.3.jar", "BOOT-INF/lib/postgresql-42.7.8.jar", "BOOT-INF/lib/spring-boot-jarmode-tools-3.5.7.jar"]
Статика: cwfr и nginx
Прямые HTTP/1.1 keep-alive запросы, четыре воркера, четыре физических P-ядра (CPU 0,2,4,6), 512 МиБ на сервер, буферы 16 КиБ, page cache, без gzip/access log. Клиент — CPU 8,10,12,14.
Пять повторов по 15 с с прогревом 1 с на сценарий.
Файлы: 200 Б, 20 КиБ, 1 МиБ.
Диапазоны: начальная половина, последняя четверть, multipart из первой и последней четверти.
Ниже итоговые cwfr и nginx при 64 соединениях.
Раздел на главной позволяет выбрать все четыре числа соединений и варианты диапазонов. Условия отличаются от серии JSON.
| Файл | Ответ | cwfr, req/s | nginx, req/s | cwfr p99, мс | nginx p99, мс |
|---|---|---|---|---|---|
| 200 Б | full | 480 307 | 500 375 | 0,263 | 0,667 |
| 200 Б | prefix_half | 464 506 | 492 762 | 0,277 | 0,206 |
| 200 Б | suffix_quarter | 463 087 | 491 316 | 0,257 | 0,207 |
| 200 Б | multipart_quarters | 388 871 | 400 835 | 0,273 | 0,210 |
| 20 КиБ | full | 432 924 | 464 927 | 0,366 | 1,138 |
| 20 КиБ | prefix_half | 428 125 | 469 011 | 0,313 | 0,194 |
| 20 КиБ | suffix_quarter | 431 635 | 473 936 | 0,265 | 0,200 |
| 20 КиБ | multipart_quarters | 333 483 | 379 143 | 0,364 | 0,247 |
| 1 МиБ | full | 25 798 | 25 781 | 2,508 | 2,514 |
| 1 МиБ | prefix_half | 51 016 | 50 679 | 1,267 | 1,265 |
| 1 МиБ | suffix_quarter | 110 552 | 101 434 | 1,786 | 0,687 |
| 1 МиБ | multipart_quarters | 51 481 | 52 062 | 1,273 | 1,252 |