Нагрузочное тестирование панелей управления игровыми серверами

Содержание
Эта статья посвящена нагрузочному тестированию пяти популярных панелей управления игровыми серверами: GameAP 3, GameAP 4, PufferPanel, Pterodactyl и Pelican. Все панели тестируются на одном и том же железе, в максимально близких условиях; там, где условия выровнять не удалось, это явно отмечено в разделе об ограничениях.
Дисклеймер. Статья выходит в блоге GameAP, и написал её разработчик, которому принадлежат две из пяти тестируемых панелей: GameAP 3 и GameAP 4. Это конфликт интересов, и вы вправе ожидать предвзятости. Поэтому тест устроен так, чтобы его можно было проверить: скрипты k6, конфигурации, сырые отчёты k6 и метрики мониторинга всех прогонов опубликованы в репозитории на GitHub. Методологию можно разобрать по шагам, а тест повторить на своём железе. Если вам покажется, что какой-то панели досталась неверная конфигурация, а какой-то вывод натянут, откройте issue: будет перепроверено и опубликовано исправление. И оговорка для тех, кто пришёл за коротким ответом: да, GameAP 4 показал здесь лучшие цифры.
Коротко:
- На типовой нагрузке (10–100 одновременных пользователей) все пять панелей работают без единой ошибки; различается латентность: единицы миллисекунд у Go-панелей, около 9 мс у GameAP 3, десятки миллисекунд у Pterodactyl и Pelican.
- Потолок пропускной способности на этом стенде:
- 1126 запросов/сек у GameAP 4
- 696 запросов/сек у PufferPanel
- 394 запросов/сек у GameAP 3
- 93 запросов/сек у Pterodactyl
- 76 запросов/сек у Pelican.
- Под перегрузкой панели ломаются по-разному: Go-панели начинают отдавать ошибки, PHP-панели ошибок не отдают вовсе, но время ответа вырастает до секунд и десятков секунд.
- Самое неожиданное: у Pterodactyl и Pelican при насыщении MySQL занимает почти целое ядро CPU, хотя у GameAP 3 на том же MySQL с теми же настройками СУБД занята втрое меньше при вдвое большем числе запросов в секунду.
Цели #
- Найти точку отказа: предел, на котором панель ещё полноценно работает.
- Сравнить альтернативы при максимально близких условиях.
- Сравнить GameAP 3 и GameAP 4: что именно дало переписывание с PHP на Go.
Помимо общего сравнения всех пяти панелей, отдельно интересны три группы:
- GameAP 3.x против GameAP 4.x: полное переписывание проекта на Go и обновлённая архитектура.
- GameAP 4.x против PufferPanel: сравнение панелей, написанных на Go.
- Pterodactyl против Pelican: производительность первоначальной панели и её форка.
Панели #
| Панель | Версия | Стек | СУБД | Демон |
|---|---|---|---|---|
| GameAP 4.x | 4.x | Go | PostgreSQL | gameap-daemon |
| PufferPanel | 3.x | Go | PostgreSQL | встроенный |
| GameAP 3.x | 3.x | PHP 8.4 / Laravel | MySQL 8.0 | gameap-daemon |
| Pterodactyl | 1.11.x | PHP 8.4 / Laravel | MySQL 8.0 | Wings (Docker) |
| Pelican | 1.0.x | PHP 8.4 / Laravel, форк Pterodactyl | MySQL 8.0 | Wings (Docker) |
У всех трёх PHP-панелей дополнительно установлен Redis (кеш и сессии). Версии зафиксированы с точностью до мажорных веток по состоянию на апрель 2026 года, когда выполнялись прогоны.
Что тестируется #
- HTTP/API-латентность при разных уровнях конкурентности: load-тестирование (10–100 VUs);
- поведение под перегрузкой (деградация, ошибки, потребление ресурсов): stress-тестирование (800–1200 VUs);
- потолок пропускной способности без пауз между запросами: throughput-тестирование.
За рамками статьи остаются:
- запросы на запись;
- UX, функциональность, безопасность, экосистема;
- работа с реальными игровыми серверами и их файлами;
- долгосрочная стабильность: soak- и spike-тесты не проводились.
Стенд #
Сервер (bare-metal, Selectel):
- CPU: Intel Xeon E-2456 (Raptor Lake, 6C/12T, 3,3 ГГц base / 5,1 ГГц turbo, 18 MB L3);
- RAM: 32 GB DDR5 ECC (2×16 GB, 4400 MT/s);
- диски: 2× Samsung 990 PRO 1TB NVMe в mdadm RAID1;
- гипервизор: Proxmox VE 9.1.5 на Debian 13, ядро 6.17.9-1-pve.
Конфигурация виртуальных машин #
| ВМ | vCPU | RAM | Диск | Назначение |
|---|---|---|---|---|
| Панель | 4 | 8 GB | 40 GB | панель управления (API), Ubuntu 24.04 LTS |
| Демон | 6 | 12 GB | 80 GB | демон/агент игровых серверов, Ubuntu 24.04 LTS |
| k6-runner | 4 | 4 GB | — | генератор нагрузки |
| Мониторинг | 2 | 4 GB | — | Prometheus + Grafana |
Тюнинг хоста #
- CPU governor: performance;
- C-states ограничены до C1;
- Turbo Boost активен;
- swap отключён на всех виртуальных машинах.
Методология #
Панели тестируются последовательно, по одной: на время теста все остальные ВМ выключены, чтобы исключить взаимное влияние. Во время прогона работают только панель (API), демон игровых серверов, генератор нагрузки k6 и мониторинг.
Каждая панель прошла три полных независимых прогона всей серии профилей (18–19 апреля 2026 года). Все числа в статье — медианы трёх прогонов, если явно не указано иное.
Порядок прогона для каждой панели: старт двух ВМ (панель и демон) → перезапуск сервисов → прогревочный прогон smoke-сценария (1 VU, 30 с) → профили нагрузки по порядку. Перед каждым профилем сервисы панели перезапускаются, после профиля — пауза 60 с. Наборы перезапускаемых сервисов при этом различаются: у PHP-панелей это php-fpm, nginx и MySQL (у GameAP 3 ещё и Redis), у PufferPanel само приложение, у GameAP 4 только nginx. Это асимметрия методологии, подробнее в ограничениях.
Профили нагрузки #
| Профиль | VUs | Длительность | Тип теста |
|---|---|---|---|
| smoke | 1 | 30 с | латентность без конкуренции |
| baseline | 10 | 4,5 мин | load |
| load | 20 → 50 → 100 | 11 мин | load |
| stress | 50 → 100 → 200 → 400 → 800 | 10 мин | stress |
| stress-1000 | 200 → 500 → 1000, удержание 5 мин | 9 мин | stress |
| stress-1200 | 200 → 500 → 800 → 1200, удержание 5 мин | 10 мин | stress |
| max-throughput | 100, без пауз | 2 мин 40 с | throughput |
Сценарий #
Каждая итерация выполняет три GET-запроса, которые реальные пользователи делают чаще всего: список серверов, детали случайного сервера из списка и его статус. Между запросами пауза 0,3–0,8 с, в конце итерации 1–3 с. В профиле max-throughput те же три запроса идут без пауз. Запросов на изменение данных (POST, PUT, DELETE и т. д.) в тесте нет.
| Панель | Список | Детали | Статус | Записей в ответе списка |
|---|---|---|---|---|
| GameAP 3.x | /api/servers | /api/servers/{id} | тот же запрос, что и детали¹ | 102 |
| GameAP 4.x | /api/servers | /api/servers/{id} | /api/servers/{id}/status | 102 |
| PufferPanel | /api/servers | /api/servers/{id} | /api/servers/{id}/status | 20 (первая страница) |
| Pterodactyl | /api/client | /api/client/servers/{id} | …/{id}/resources | 50 (первая страница) |
| Pelican | /api/client | /api/client/servers/{id} | …/{id}/resources | 50 (первая страница) |
¹ Отдельного эндпоинта статуса в GameAP 3.x нет, поэтому запрос деталей выполняется повторно.
На каждой панели создано по 100 одинаковых серверов-пустышек (mock-скрипт, печатающий время; серверы не устанавливались и не запускались). Ответы списочных API при этом различаются: GameAP отдаёт все записи разом (в базе стенда их было 102), Pterodactyl и Pelican — первую страницу из 50, PufferPanel — первую страницу из 20. Средний объём ответа на load-профиле — 13–16 KB на запрос у четырёх панелей и 1,6 KB у PufferPanel. Прямое сравнение латентности list_servers между панелями поэтому не вполне корректно; это одна из главных оговорок теста.
Аутентификация и лимиты #
GameAP 3/4, Pterodactyl и Pelican используют API-ключ (Bearer). PufferPanel использует OAuth2 client credentials: токен получается один раз в setup() и переиспользуется всеми VU. Сам OAuth-запрос (~58 мс) попадает в статистику каждого профиля, потому что setup() выполняется при каждом запуске k6. В коротком smoke-профиле (31–34 запроса) он поднимает среднюю латентность PufferPanel с ~2 до ~3,7 мс при неизменной медиане. На baseline это один запрос из ~2 200, примерно +0,03 мс (~2 %) к средней, медиана и перцентили не затронуты; на профилях длиннее влияние пренебрежимо.
У Pterodactyl и Pelican API rate limits подняты до 10 000 запросов в минуту, иначе тест упёрся бы в лимитер, а не в панель.
Тюнинг PHP-панелей (одинаковый у GameAP 3, Pterodactyl и Pelican) #
; PHP-FPM
pm = dynamic, pm.max_children = 50, pm.start_servers = 10
; OPcache
opcache.memory_consumption = 256, opcache.jit = tracing, opcache.jit_buffer_size = 128M
; MySQL
innodb_buffer_pool_size = 2G, max_connections = 200, innodb_flush_log_at_trx_commit = 2
Инструменты #
- k6 v1.7.1; таймаут запроса по умолчанию 60 с;
- Prometheus, node_exporter 1.8.2 (метрики ВМ, шаг 15 с), process_exporter 0.8.7 (метрики процессов, шаг 30 с).
Закрытая модель нагрузки #
k6 работает по closed-loop-модели: виртуальный пользователь не отправляет следующий запрос, пока не получил ответ на предыдущий. Когда панель замедляется, фактическая интенсивность нагрузки на неё автоматически снижается. В открытой системе (реальные пользователи, автообновляющиеся дашборды, интеграции) запросы продолжали бы поступать независимо от ответов, и деградировавшей панели было бы только хуже. Читая стресс-результаты, держите это в голове: цифры замедлившихся панелей — оптимистичная оценка. Подробнее об эффекте: coordinated omission.
Наблюдения при разворачивании #
Ресурсы ВМ панели на smoke-профиле (1 VU, база уже наполнена 100 серверами); пик за окно профиля, медиана трёх прогонов:
| Панель | CPU | RAM |
|---|---|---|
| GameAP 4.x | 0,4 % | 449 MB |
| PufferPanel | 0,6 % | 462 MB |
| GameAP 3.x | 3,2 % | 1 049 MB |
| Pterodactyl | 2,3 % | 1 096 MB |
| Pelican | 2,9 % | 1 177 MB |
RAM указана по всей виртуальной машине (MemTotal − MemAvailable), включая ОС, СУБД и вспомогательные сервисы.
Замечания, накопившиеся при разворачивании стенда:
- Pterodactyl и Pelican не умеют работать за NAT (ни панель, ни Wings): браузер подключается к Wings напрямую по HTTP/HTTPS.
- У Pelican после изменения настроек приходится пересобирать кеш конфигурации, иначе панель падает.
Результаты #
Все числа ниже — медианы трёх прогонов; сырые отчёты каждого прогона лежат в репозитории. О воспроизводимости: на профилях baseline, load и max-throughput медианная латентность между прогонами расходится не более чем на 6,1 %, RPS — не более чем на 2,7 %. Smoke слишком короткий (28–34 запроса за прогон), там разброс медианы достигает 22 %. На стресс-профилях поведение ожидаемо менее стабильно: например, медиана GameAP 4 на stress-1200 по прогонам — 23,7 / 24,6 / 31,9 мс.
Латентность по уровням нагрузки #
Медианная латентность, мс:
| Профиль | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
| smoke (1 VU) | 1,11 | 2,01 | 20,2 | 26,9 | 29,0 |
| baseline (10 VUs) | 0,82 | 1,54 | 9,24 | 12,7 | 16,0 |
| load (до 100 VUs) | 0,59 | 1,37 | 8,78 | 20,7 | 54,5 |
| stress (до 800 VUs) | 0,57 | 1,45 | 27,7 | 1 144 | 1 520 |
| stress-1000 | 0,76 | 114 | 1 481 | 7 664 | 10 501 |
| stress-1200 | 24,6 | 97,2 | 1 958 | 10 455 | 12 807 |
95-й перцентиль, мс:
| Профиль | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
| smoke (1 VU) | 1,69 | 4,98 | 29,2 | 87,0 | 106 |
| baseline (10 VUs) | 1,45 | 2,08 | 19,9 | 79,4 | 97,0 |
| load (до 100 VUs) | 1,20 | 1,85 | 13,2 | 154 | 473 |
| stress (до 800 VUs) | 2,92 | 58,2 | 908 | 9 146 | 11 221 |
| stress-1000 | 15,2 | 319 | 1 583 | 13 607 | 15 247 |
| stress-1200 | 283 | 330 | 2 078 | 14 144 | 17 477 |
Что здесь видно.
До 100 VUs включительно все пять панелей отвечают без единой ошибки, и вопрос только в скорости: Go-панели держатся в пределах 2 мс по медиане, GameAP 3 — около 9 мс, Pterodactyl — 13–21 мс, Pelican — 16–55 мс. У Pelican на load-профиле медиана уже растёт (54,5 мс, p95 — 473 мс): как будет видно в разделе о ресурсах, на 100 VUs он практически упирается в CPU.
На стресс-профилях группы расходятся радикально. GameAP 4 проходит 800 и 1000 VUs без деградации медианы (0,6–0,8 мс), PufferPanel на 1000 VUs замедляется до 114 мс и начинает отдавать ошибки, GameAP 3 держит 800 VUs с медианой 28 мс (p95 — 0,9 с), а на 1000+ уходит в 1,5–2 с. Pterodactyl и Pelican на 800 VUs уже отвечают за секунды, на 1000–1200 — за 8–13 с по медиане.
Обратите внимание на разрыв между медианой и p95 у PHP-панелей уже на малой нагрузке: у Pterodactyl на baseline медиана 12,7 мс, а p95 — 79 мс. Хвост из медленных ответов у них длинный даже там, где панель в целом справляется.
Потолок пропускной способности #
Профиль max-throughput: 100 VUs выполняют те же три запроса без пауз: 30 с разгона, 2 мин удержания, 10 с спада. RPS считается как среднее за всё окно, включая разгон.
| Панель | RPS | Средняя, мс | Медиана, мс | p95, мс | Ошибки |
|---|---|---|---|---|---|
| GameAP 4.x | 1 126 | 77,6 | 68,9 | 179 | 0 |
| PufferPanel | 696 | 126 | 121 | 257 | 0 |
| GameAP 3.x | 394 | 222 | 241 | 302 | 0 |
| Pterodactyl | 93 | 941 | 766 | 1 825 | 0 |
| Pelican | 76 | 1 160 | 945 | 2 291 | 0 |
Ни одна панель не отдала ни одной ошибки, но пропускная способность крайних различается в 15 раз (1126 против 76 запросов/с). Интересно сопоставить это с загрузкой CPU: в этом профиле все панели работают на пределе (95–100 % CPU виртуальной машины — см. таблицу ресурсов). Утилизация одинаковая, а результат кратно разный: сравнивать панели по «загрузке процессора» бессмысленно, важно, сколько работы панель успевает сделать на ядро.
Поведение под перегрузкой #
Доля неуспешных запросов (HTTP ≥ 400), % от всех запросов профиля:
| Профиль | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
| load (до 100 VUs) | 0 | 0 | 0 | 0 | 0 |
| stress (до 800 VUs) | 0 | 0,09 | 0 | 0 | 0 |
| stress-1000 | < 0,01 | 21,3 | 0 | 0 | 0 |
| stress-1200 | 15,2 | 34,6 | 0 | 0 | 0 |
Точки отказа по этим данным такие. PufferPanel первым начинает отдавать ошибки: единичные (0,08–0,12 %) уже на 800 VUs, 21 % на 1000, 35 % на 1200 (по запросу списка до 40 %). GameAP 4 проходит 1000 VUs практически чисто (по медиане ноль ошибок, в одном из трёх прогонов 0,011 %), а на 1200 VUs отдаёт 14,3–15,5 % ошибок. PHP-панели не отдают ошибок вовсе — ни на одном профиле.
Но «0 % ошибок» здесь не значит «панель работает». На stress-1200 у GameAP 3 p95 — 2,1 с, у Pterodactyl — 14,1 с, у Pelican — 17,5 с. Формально каждый запрос в итоге получает ответ 200 (k6 ждёт до 60 с), фактически панелью с ответами по 10–17 секунд пользоваться нельзя. Это два разных режима деградации, а не «PHP выдерживает, Go — нет»:
- Go-панели — fail fast: часть запросов быстро завершается ошибкой, остальные обслуживаются с приемлемой латентностью (медиана GameAP 4 на 1200 VUs — 25 мс, PufferPanel — 97 мс). Клиент сразу знает, что серверу плохо.
- PHP-панели — очередь: PHP-FPM ставит запросы в очередь, ошибок нет, но время ответа растёт неограниченно. Клиент ждёт, не зная, дождётся ли.
Какой режим «правильнее» — вопрос требований, а не бенчмарка. Практическое следствие одно: перегрузку PHP-панели не увидеть в мониторинге ошибок, только в латентности.
Достигнутый RPS на стресс-профилях:
| Профиль | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
| stress (до 800 VUs) | 259 | 257 | 210 | 82 | 68 |
| stress-1000 | 716 | 615 | 341 | 90 | 73 |
| stress-1200 | 764 | 699 | 349 | 90 | 74 |
Важно читать эту таблицу правильно: из-за пауз между запросами и плавного набора VUs stress-профиль физически не может дать больше ~260 запросов/с (среднее по времени число активных VUs ≈ 268, на итерацию из трёх запросов приходится ~3,1 с пауз). GameAP 4 и PufferPanel упёрлись в потолок профиля, а не в собственный: 259 и 257. GameAP 3 успевает обслужить 210. А Pterodactyl и Pelican на любом стресс-профиле выдают примерно свой max-throughput (82–90 и 68–74 запросов/с против потолков 93 и 76): панель отдаёт столько, сколько может, остальное копится в очереди.
Ресурсы и узкие места #
Пиковая загрузка CPU виртуальной машины панели, %:
| Профиль | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
| smoke (1 VU) | 0,4 | 0,6 | 3,2 | 2,3 | 2,9 |
| baseline (10 VUs) | 0,7 | 0,9 | 4,8 | 8,9 | 10,9 |
| load (до 100 VUs) | 2,4 | 3,8 | 25,7 | 81,2 | 96,8 |
| stress (до 800 VUs) | 20,4 | 65,3 | 100 | 100 | 100 |
| stress-1000 | 40,0 | 95,6 | 100 | 100 | 100 |
| stress-1200 | 87,7 | 96,1 | 100 | 100 | 100 |
| max-throughput | 96,1 | 95,3 | 100 | 100 | 100 |
Ключевая строка — load: та самая «рабочая» нагрузка в 100 одновременных пользователей, которую все панели проходят без ошибок, стоит GameAP 4 и PufferPanel 2–4 % CPU, GameAP 3 — 26 %, Pterodactyl — 81 %, Pelican — 97 %. Pterodactyl и Pelican на этом профиле уже работают на грани насыщения — запаса на пики у них не остаётся.
Куда уходит CPU при перегрузке — процессы на stress-профиле (800 VUs), пик за окно, среднее прогонов 2–3:
| Процесс | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
| Приложение (Go / php-fpm) | 31,5 | 73,1 | 318 | 243 | 260 |
| СУБД (PostgreSQL / MySQL) | 2,9 | 9,5 | 31,4 | 109 | 94,3 |
100 % = одно ядро, всего 4 vCPU. Nginx во всех прогонах ≤ 3,2 %; Redis там, где его видел process_exporter, — ≤ 5,1 % (покрытие Redis-процесса мониторингом получилось неполным — в части прогонов process_exporter его не отслеживал; на общую картину это не влияет, но в таблицу он не включён).
Самое интересное здесь — строка СУБД. У Pterodactyl и Pelican MySQL занимает 94–109 % CPU, то есть почти целое ядро, при 68–82 обслуженных запросах в секунду. У GameAP 3 тот же MySQL 8.0 с теми же настройками занят на 31 % — при 210 запросах в секунду. В пересчёте на один запрос Pterodactyl и Pelican тратят примерно в девять раз больше процессорного времени СУБД, чем GameAP 3. Похоже, что узкое место этих панелей — не PHP сам по себе, а работа с базой данных. Причина не профилировалась и остаётся открытым вопросом; напрашивается разбор запросов списочных эндпоинтов через EXPLAIN.
Пиковая RAM виртуальной машины, MB:
| Профиль | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
| smoke (1 VU) | 449 | 462 | 1 049 | 1 096 | 1 177 |
| stress (до 800 VUs) | 480 | 539 | 1 288 | 1 463 | 1 606 |
| stress-1200 | 701 | 744 | 1 354 | 1 469 | 1 610 |
| max-throughput | 641 | 672 | 1 342 | 1 445 | 1 556 |
RSS процессов на stress-800 (среднее прогонов 2–3): приложение — 65 MB у GameAP 4 и 107 MB у PufferPanel против 2,7–4,2 GB суммарного RSS пятидесяти воркеров php-fpm; СУБД — 107 MB PostgreSQL у GameAP 4 против ~613–641 MB MySQL. Две оговорки: RSS воркеров php-fpm многократно учитывает общую память (реальное потребление ВМ — в таблице выше), а RSS PostgreSQL у PufferPanel заметно колебался между прогонами (721 MB в первом, ~440 MB во втором и третьем).
И одна аномалия, которая честно осталась неразобранной: PufferPanel единственный активно пишет на диск под нагрузкой: пики 140–150 IOPS на записи против 4 у GameAP 4 и 21–24 у остальных. Причина (логи? аудит? особенности работы с PostgreSQL?) не выяснялась.
Что видно по отдельным эндпоинтам #
Медианная латентность по эндпоинтам на load-профиле, мс:
| Эндпоинт | GameAP 4.x | PufferPanel | GameAP 3.x | Pterodactyl | Pelican |
|---|---|---|---|---|---|
list_servers | 0,87 | 1,41 | 11,1 | 87,3 | 141 |
server_details | 0,58 | 0,74 | 8,34 | 12,7 | 25,6 |
server_status | 0,38 | 1,49 | 8,34 | 11,5 | 20,9 |
Список серверов — самый тяжёлый запрос у всех панелей, но у Pterodactyl и Pelican разрыв драматический: список в 7–8 раз медленнее деталей (87 и 141 мс против 13 и 26 мс). Именно списочный запрос первым деградирует под нагрузкой.
Стоит напомнить оговорку из методологии: объём ответа списка у панелей разный (102 записи у GameAP, 50 у Pterodactyl/Pelican, 20 у PufferPanel), поэтому сравнивать строку list_servers между панелями некорректно. Корректные наблюдения здесь — соотношение эндпоинтов внутри одной панели и тот факт, что GameAP 4 отдаёт полный список из 102 записей (~13 KB) быстрее, чем любая PHP-панель отдаёт первую страницу.
Три сравнения из целей теста #
GameAP 3 → GameAP 4. Ради этого переписывание и затевалось: медиана на baseline — 9,24 против 0,82 мс (в 11 раз), на load — 8,78 против 0,59 мс (в 15 раз), потолок пропускной способности — 394 против 1126 запросов/с (в 2,9 раза), память всей ВМ — 1,0–1,4 GB против 0,45–0,70 GB, CPU на load — 26 против 2,4 %.
GameAP 4 против PufferPanel. Обе панели на Go и PostgreSQL, и обе на порядок быстрее PHP-группы. Между собой: GameAP 4 быстрее по медиане в 1,9–2,3 раза на baseline/load и в 1,6 раза по потолку RPS (1126 против 696), позже ломается под перегрузкой (15 % ошибок на 1200 VUs против 21 % уже на 1000 и первых единичных на 800 у PufferPanel) и почти не пишет на диск. При этом стоит помнить, что в этом сценарии PufferPanel отдаёт на порядок меньше данных на запрос списка (20 записей, ~1,6 KB против 102 записей, ~13 KB), то есть разрыв измерен на более лёгкой для PufferPanel работе.
Pterodactyl против Pelican. Форк оказался медленнее оригинала на каждом профиле: на load медиана 54,5 против 20,7 мс, p95 — 473 против 154 мс, потолок — 76 против 93 запросов/с, насыщение CPU наступает раньше (97 % уже на load против 81 %). По процессам у Pelican php-fpm загружен больше (260 против 243 %), а MySQL — меньше (94 против 109 %). Причины различий не разбирались; на момент теста Pelican — молодой форк (1.0.x), и его профиль производительности ещё может меняться.
Ограничения #
Список того, что ограничивает выводы этого теста.
- Разные СУБД у групп. Go-панели работали на PostgreSQL, PHP-панели — на MySQL 8.0 (в обоих случаях конфигурации, рекомендуемые разработчиками панелей). Сравнения «Go против PHP» здесь всегда означают «Go+PostgreSQL против PHP+MySQL» — вклад СУБД от вклада языка и архитектуры этот тест не отделяет. Внутри групп СУБД одинаковые.
- Разный объём ответов
list_servers. В базе у всех по 100 серверов, но GameAP отдаёт список целиком (102 записи), Pterodactyl/Pelican — первую страницу из 50, PufferPanel — из 20; объём ответа от 1,6 до 16 KB. Тест не выравнивал пагинацию под один размер страницы. Прямые сравнения латентности списка между панелями из-за этого смещены; в чью пользу, зависит от пары (PufferPanel этот перекос облегчает работу, GameAP — утяжеляет). - GameAP 3 без статус-эндпоинта:
server_statusу него — повторный запрос деталей, то есть треть сценария у GameAP 3 не эквивалентна другим панелям. - Только чтение, только API. Ни записи, ни WebSocket, ни UI; серверы-пустышки не устанавливались и не запускались, демоны на соседних ВМ фактически простаивали. Это тест HTTP/API-слоя панелей, не панелей целиком.
- Закрытая модель k6 (см. методологию): у деградировавших панелей фактическая нагрузка автоматически снижалась, поэтому их стресс-цифры — оптимистичная оценка. Таймаут запроса k6 — 60 с.
- Прогрев. Перед серией профилей выполняется один smoke-прогон (30 с), перед каждым профилем перезапускаются сервисы. У панелей, не упирающихся в CPU (GameAP 3/4, PufferPanel), средняя латентность на baseline выше, чем на более тяжёлом load (0,85 → 0,66 мс; 1,49 → 1,27; 10,9 → 9,7) — часть baseline-окна, по-видимому, ещё прогрев. На выводы это не влияет, но абсолютные числа baseline слегка завышены.
- Асимметрия перезапусков. Перед каждым профилем у PHP-панелей перезапускались php-fpm, nginx и MySQL (сброс буферпула и кешей; у GameAP 3 ещё и Redis), у PufferPanel — приложение (PostgreSQL продолжал работать), у GameAP 4 — только nginx (приложение и PostgreSQL не перезапускались). PHP-панели каждый профиль начинали «холоднее». Ramp-фазы профилей это частично компенсируют, но полностью асимметрия не устранена.
- Версии зафиксированы мажорно (GameAP 4.x / 3.x, Pterodactyl 1.11.x, Pelican 1.0.x, PufferPanel 3.x, апрель 2026). GameAP 4 функционально моложе и проще остальных: меньший объём работы на запрос может быть частью его преимущества; количественно это не оценивалось.
- Изменённые лимиты. У Pterodactyl и Pelican rate limits подняты до 10 000 запросов/мин: стандартная установка отсекала бы нагрузку раньше.
- Мониторинг. CPU и RAM — по всей ВМ с шагом 15 с (короткие пики могли сгладиться); метрики процессов — с шагом 30 с, и покрытие Redis-процесса по прогонам неполное; в статистику smoke у PufferPanel входит OAuth-запрос из
setup(). Одно железо, одна конфигурация ВМ, 100 серверов в базе — на другом железе и других объёмах данных абсолютные числа будут другими.
Выводы #
Возвращаясь к трём вопросам из целей.
Насколько различаются панели при нормальной нагрузке? На load-профиле (до 100 одновременных пользователей) все пять панелей работают без ошибок, а латентность различается на порядок и более: 0,6–1,4 мс медианы у Go-панелей, ~9 мс у GameAP 3, 21–55 мс у Pterodactyl/Pelican. Стоит сказать прямо: для человека за браузером и 55 мс — это быстро. Если у вас одна панель, десяток серверов и никакой автоматизации, любой из участников ответит «мгновенно». Разница становится практической при интеграциях и автоматизации, при массовых операциях, на дешёвом железе, и по цене этой скорости: те же 100 VUs стоят Pelican 97 % CPU, а GameAP 4 — 2,4 %.
Где точка отказа и как панель ломается? По потолку пропускной способности: 1126 (GameAP 4) → 696 (PufferPanel) → 394 (GameAP 3) → 93 (Pterodactyl) → 76 (Pelican) запросов/с. Под перегрузкой видны два режима: Go-панели быстро отдают ошибки (PufferPanel с 800–1000 VUs, GameAP 4 с 1200), PHP-панели ошибок не отдают, но отвечают за секунды и десятки секунд. Практический вывод для мониторинга: перегрузку PHP-панели видно только по латентности, алертов по ошибкам не будет.
Что является узким местом? У GameAP 4 — CPU самого приложения (СУБД почти не нагружена). У PufferPanel — приложение плюс заметная дисковая запись, причина которой не выяснялась. У GameAP 3 — php-fpm (318 % CPU при 31 % у MySQL). У Pterodactyl и Pelican картина иная: вместе с php-fpm почти целое ядро съедает MySQL — в пересчёте на запрос это примерно в девять раз больше СУБД-времени, чем у GameAP 3 на том же MySQL. Это самый интересный результат теста, и он заслуживает отдельного разбора с профилированием запросов.
Этот тест измеряет один срез: скорость HTTP/API-слоя на чтение. Он ничего не говорит о функциональности, удобстве, безопасности и экосистеме, а выбор панели определяется в том числе ими. GameAP 4 выиграл этот бенчмарк, но он и моложе всех участников; Pterodactyl проиграл по цифрам, но остаётся самой распространённой панелью с самой большой экосистемой. Что делать с этими фактами — решать вам.
Что дальше #
- Этап 2 — управление серверами: массовый старт/стоп N серверов, steady-state с работающими серверами, параллельные WebSocket-консоли, создание серверов через API. Для этого готовится fake-game-server — бинарь, имитирующий реальный игровой сервер.
- Масштабирование по объёму данных: прогоны с 1 / 100 / 1000 серверами в базе, чтобы измерить, как латентность списочных эндпоинтов зависит от размера базы.
- Открытые вопросы из этого этапа: дисковая запись PufferPanel, профилирование MySQL-запросов Pterodactyl/Pelican, разница между Pelican и Pterodactyl.
Скрипты, конфигурации и сырые данные всех прогонов — в репозитории game-panels-benchmark. Если нашли ошибку в методологии или интерпретации, откройте issue: будет перепроверено и опубликовано исправление.