Эта статья посвящена нагрузочному тестированию пяти популярных панелей управления игровыми серверами: 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 с теми же настройками СУБД занята втрое меньше при вдвое большем числе запросов в секунду.
Потолок пропускной способностибольше — лучшезапросов в секунду · медиана трёх прогонов2505007501 0001 2500GameAP 4.x: 1 126 запросов/с1 126GameAP 4.xPufferPanel: 696 запросов/с696PufferPanelGameAP 3.x: 394 запросов/с394GameAP 3.xPterodactyl: 93 запросов/с93PterodactylPelican: 76 запросов/с76Pelican

Цели #

  1. Найти точку отказа: предел, на котором панель ещё полноценно работает.
  2. Сравнить альтернативы при максимально близких условиях.
  3. Сравнить GameAP 3 и GameAP 4: что именно дало переписывание с PHP на Go.

Помимо общего сравнения всех пяти панелей, отдельно интересны три группы:

  1. GameAP 3.x против GameAP 4.x: полное переписывание проекта на Go и обновлённая архитектура.
  2. GameAP 4.x против PufferPanel: сравнение панелей, написанных на Go.
  3. Pterodactyl против Pelican: производительность первоначальной панели и её форка.

Панели #

ПанельВерсияСтекСУБДДемон
GameAP 4.x4.xGoPostgreSQLgameap-daemon
PufferPanel3.xGoPostgreSQLвстроенный
GameAP 3.x3.xPHP 8.4 / LaravelMySQL 8.0gameap-daemon
Pterodactyl1.11.xPHP 8.4 / LaravelMySQL 8.0Wings (Docker)
Pelican1.0.xPHP 8.4 / Laravel, форк PterodactylMySQL 8.0Wings (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.
Bare-metal · Selectel · Xeon E-2456 · 32 GB DDR5 · Proxmox VE 9k6-runner4 vCPU · 4 GBгенератор нагрузкиПанель (API)4 vCPU · 8 GB · 40 GBUbuntu 24.04 LTSДемон / агент6 vCPU · 12 GB · 80 GBUbuntu 24.04 LTSМониторинг2 vCPU · 4 GBPrometheus + GrafanaHTTPметрики: node_exporter → Prometheus

Конфигурация виртуальных машин #

ВМvCPURAMДискНазначение
Панель48 GB40 GBпанель управления (API), Ubuntu 24.04 LTS
Демон612 GB80 GBдемон/агент игровых серверов, Ubuntu 24.04 LTS
k6-runner44 GBгенератор нагрузки
Мониторинг24 GBPrometheus + 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ДлительностьТип теста
smoke130 слатентность без конкуренции
baseline104,5 минload
load20 → 50 → 10011 минload
stress50 → 100 → 200 → 400 → 80010 минstress
stress-1000200 → 500 → 1000, удержание 5 мин9 минstress
stress-1200200 → 500 → 800 → 1200, удержание 5 мин10 минstress
max-throughput100, без пауз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}/status102
PufferPanel/api/servers/api/servers/{id}/api/servers/{id}/status20 (первая страница)
Pterodactyl/api/client/api/client/servers/{id}…/{id}/resources50 (первая страница)
Pelican/api/client/api/client/servers/{id}…/{id}/resources50 (первая страница)

¹ Отдельного эндпоинта статуса в 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 серверами); пик за окно профиля, медиана трёх прогонов:

ПанельCPURAM
GameAP 4.x0,4 %449 MB
PufferPanel0,6 %462 MB
GameAP 3.x3,2 %1 049 MB
Pterodactyl2,3 %1 096 MB
Pelican2,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 мс.

Латентность по уровням нагрузки #

Медианная латентность по уровням нагрузкименьше — лучшемс, логарифмическая шкала · медиана трёх прогонов1 мс10 мс100 мс1 с10 с11010080010001200целевой максимум VUs профиляGameAP 4.x — 1 VUs: 1,11 мсGameAP 4.x — 10 VUs: 0,82 мсGameAP 4.x — 100 VUs: 0,59 мсGameAP 4.x — 800 VUs: 0,57 мсGameAP 4.x — 1000 VUs: 0,76 мсGameAP 4.x — 1200 VUs: 24,6 мсPufferPanel — 1 VUs: 2,01 мсPufferPanel — 10 VUs: 1,54 мсPufferPanel — 100 VUs: 1,37 мсPufferPanel — 800 VUs: 1,45 мсPufferPanel — 1000 VUs: 114 мсPufferPanel — 1200 VUs: 97,2 мсGameAP 3.x — 1 VUs: 20,2 мсGameAP 3.x — 10 VUs: 9,24 мсGameAP 3.x — 100 VUs: 8,78 мсGameAP 3.x — 800 VUs: 27,7 мсGameAP 3.x — 1000 VUs: 1 481 мсGameAP 3.x — 1200 VUs: 1 958 мсPterodactyl — 1 VUs: 26,9 мсPterodactyl — 10 VUs: 12,7 мсPterodactyl — 100 VUs: 20,7 мсPterodactyl — 800 VUs: 1 144 мсPterodactyl — 1000 VUs: 7 664 мсPterodactyl — 1200 VUs: 10 455 мсPelican — 1 VUs: 29,0 мсPelican — 10 VUs: 16,0 мсPelican — 100 VUs: 54,5 мсPelican — 800 VUs: 1 520 мсPelican — 1000 VUs: 10 501 мсPelican — 1200 VUs: 12 807 мсPelicanPterodactylGameAP 3.xPufferPanelGameAP 4.x

Медианная латентность, мс:

ПрофильGameAP 4.xPufferPanelGameAP 3.xPterodactylPelican
smoke (1 VU)1,112,0120,226,929,0
baseline (10 VUs)0,821,549,2412,716,0
load (до 100 VUs)0,591,378,7820,754,5
stress (до 800 VUs)0,571,4527,71 1441 520
stress-10000,761141 4817 66410 501
stress-120024,697,21 95810 45512 807

95-й перцентиль, мс:

ПрофильGameAP 4.xPufferPanelGameAP 3.xPterodactylPelican
smoke (1 VU)1,694,9829,287,0106
baseline (10 VUs)1,452,0819,979,497,0
load (до 100 VUs)1,201,8513,2154473
stress (до 800 VUs)2,9258,29089 14611 221
stress-100015,23191 58313 60715 247
stress-12002833302 07814 14417 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 считается как среднее за всё окно, включая разгон.

Потолок пропускной способности (max-throughput)больше — лучшезапросов в секунду · 100 VUs без пауз · медиана трёх прогонов · 0 % ошибок у всех02505007501 0001 250GameAP 4.xGameAP 4.x: 1 126 запросов/с1 126PufferPanelPufferPanel: 696 запросов/с696GameAP 3.xGameAP 3.x: 394 запросов/с394PterodactylPterodactyl: 93 запросов/с93PelicanPelican: 76 запросов/с76
ПанельRPSСредняя, мсМедиана, мсp95, мсОшибки
GameAP 4.x1 12677,668,91790
PufferPanel6961261212570
GameAP 3.x3942222413020
Pterodactyl939417661 8250
Pelican761 1609452 2910

Ни одна панель не отдала ни одной ошибки, но пропускная способность крайних различается в 15 раз (1126 против 76 запросов/с). Интересно сопоставить это с загрузкой CPU: в этом профиле все панели работают на пределе (95–100 % CPU виртуальной машины — см. таблицу ресурсов). Утилизация одинаковая, а результат кратно разный: сравнивать панели по «загрузке процессора» бессмысленно, важно, сколько работы панель успевает сделать на ядро.

Поведение под перегрузкой #

Доля неуспешных запросов на стресс-профиляхменьше — лучше% всех запросов (HTTP ≥ 400) · медиана трёх прогонов0%10%20%30%40%PufferPanel — 800 VUs: 0,09%800 VUsPufferPanel — 1000 VUs: 21,3%1000 VUsGameAP 4.x — 1200 VUs: 15,2%PufferPanel — 1200 VUs: 34,6%1200 VUs00,09000< 0,0121,300015,234,6000GameAP 4.xPufferPanelGameAP 3.xPterodactylPelican

Доля неуспешных запросов (HTTP ≥ 400), % от всех запросов профиля:

ПрофильGameAP 4.xPufferPanelGameAP 3.xPterodactylPelican
load (до 100 VUs)00000
stress (до 800 VUs)00,09000
stress-1000< 0,0121,3000
stress-120015,234,6000

Точки отказа по этим данным такие. 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.xPufferPanelGameAP 3.xPterodactylPelican
stress (до 800 VUs)2592572108268
stress-10007166153419073
stress-12007646993499074

Важно читать эту таблицу правильно: из-за пауз между запросами и плавного набора 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.xPufferPanelGameAP 3.xPterodactylPelican
smoke (1 VU)0,40,63,22,32,9
baseline (10 VUs)0,70,94,88,910,9
load (до 100 VUs)2,43,825,781,296,8
stress (до 800 VUs)20,465,3100100100
stress-100040,095,6100100100
stress-120087,796,1100100100
max-throughput96,195,3100100100

Ключевая строка — load: та самая «рабочая» нагрузка в 100 одновременных пользователей, которую все панели проходят без ошибок, стоит GameAP 4 и PufferPanel 2–4 % CPU, GameAP 3 — 26 %, Pterodactyl — 81 %, Pelican — 97 %. Pterodactyl и Pelican на этом профиле уже работают на грани насыщения — запаса на пики у них не остаётся.

Куда уходит CPU при перегрузке — процессы на stress-профиле (800 VUs), пик за окно, среднее прогонов 2–3:

CPU по процессам на стресс-профиле (800 VUs)меньше — лучшепик за окно профиля · 400 % = 4 vCPU · среднее прогонов 2–30%100%200%300%400%GameAP 4.xGameAP 4.x — gameap: 31,5% CPU31,5GameAP 4.x — postgresql: 2,9% CPU2,9PufferPanelPufferPanel — pufferpanel: 73,1% CPU73,1PufferPanel — postgresql: 9,5% CPU9,5GameAP 3.xGameAP 3.x — php-fpm: 318% CPU318GameAP 3.x — mysqld: 31,4% CPU31,4PterodactylPterodactyl — php-fpm: 243% CPU243Pterodactyl — mysqld: 109% CPU109PelicanPelican — php-fpm: 260% CPU260Pelican — mysqld: 94,3% CPU94,3приложение (Go / php-fpm)СУБД (PostgreSQL / MySQL)
ПроцессGameAP 4.xPufferPanelGameAP 3.xPterodactylPelican
Приложение (Go / php-fpm)31,573,1318243260
СУБД (PostgreSQL / MySQL)2,99,531,410994,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.xPufferPanelGameAP 3.xPterodactylPelican
smoke (1 VU)4494621 0491 0961 177
stress (до 800 VUs)4805391 2881 4631 606
stress-12007017441 3541 4691 610
max-throughput6416721 3421 4451 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.xPufferPanelGameAP 3.xPterodactylPelican
list_servers0,871,4111,187,3141
server_details0,580,748,3412,725,6
server_status0,381,498,3411,520,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), и его профиль производительности ещё может меняться.

Ограничения #

Список того, что ограничивает выводы этого теста.

  1. Разные СУБД у групп. Go-панели работали на PostgreSQL, PHP-панели — на MySQL 8.0 (в обоих случаях конфигурации, рекомендуемые разработчиками панелей). Сравнения «Go против PHP» здесь всегда означают «Go+PostgreSQL против PHP+MySQL» — вклад СУБД от вклада языка и архитектуры этот тест не отделяет. Внутри групп СУБД одинаковые.
  2. Разный объём ответов list_servers. В базе у всех по 100 серверов, но GameAP отдаёт список целиком (102 записи), Pterodactyl/Pelican — первую страницу из 50, PufferPanel — из 20; объём ответа от 1,6 до 16 KB. Тест не выравнивал пагинацию под один размер страницы. Прямые сравнения латентности списка между панелями из-за этого смещены; в чью пользу, зависит от пары (PufferPanel этот перекос облегчает работу, GameAP — утяжеляет).
  3. GameAP 3 без статус-эндпоинта: server_status у него — повторный запрос деталей, то есть треть сценария у GameAP 3 не эквивалентна другим панелям.
  4. Только чтение, только API. Ни записи, ни WebSocket, ни UI; серверы-пустышки не устанавливались и не запускались, демоны на соседних ВМ фактически простаивали. Это тест HTTP/API-слоя панелей, не панелей целиком.
  5. Закрытая модель k6 (см. методологию): у деградировавших панелей фактическая нагрузка автоматически снижалась, поэтому их стресс-цифры — оптимистичная оценка. Таймаут запроса k6 — 60 с.
  6. Прогрев. Перед серией профилей выполняется один smoke-прогон (30 с), перед каждым профилем перезапускаются сервисы. У панелей, не упирающихся в CPU (GameAP 3/4, PufferPanel), средняя латентность на baseline выше, чем на более тяжёлом load (0,85 → 0,66 мс; 1,49 → 1,27; 10,9 → 9,7) — часть baseline-окна, по-видимому, ещё прогрев. На выводы это не влияет, но абсолютные числа baseline слегка завышены.
  7. Асимметрия перезапусков. Перед каждым профилем у PHP-панелей перезапускались php-fpm, nginx и MySQL (сброс буферпула и кешей; у GameAP 3 ещё и Redis), у PufferPanel — приложение (PostgreSQL продолжал работать), у GameAP 4 — только nginx (приложение и PostgreSQL не перезапускались). PHP-панели каждый профиль начинали «холоднее». Ramp-фазы профилей это частично компенсируют, но полностью асимметрия не устранена.
  8. Версии зафиксированы мажорно (GameAP 4.x / 3.x, Pterodactyl 1.11.x, Pelican 1.0.x, PufferPanel 3.x, апрель 2026). GameAP 4 функционально моложе и проще остальных: меньший объём работы на запрос может быть частью его преимущества; количественно это не оценивалось.
  9. Изменённые лимиты. У Pterodactyl и Pelican rate limits подняты до 10 000 запросов/мин: стандартная установка отсекала бы нагрузку раньше.
  10. Мониторинг. 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: будет перепроверено и опубликовано исправление.