Хостинг продают по памяти, потому что память легко посчитать. Большинство игровых серверов упирается в то, как быстро одно ядро CPU успевает завершить шаг симуляции, а это трудно посчитать и ещё труднее рекламировать. Из-за этого расхождения добавление гигабайтов к тормозящему серверу так часто не меняет ничего, а апгрейд, который действительно помогает, иногда оказывается дешевле того, который не помогает. Для игроков две проблемы выглядят одинаково, а в цифрах не похожи вовсе, поэтому всё мастерство в том, чтобы знать, на какие цифры смотреть. Когда знаешь, где они лежат, это занимает около тридцати секунд.
Что делает каждый из ресурсов#
Память хранит состояние. Загруженный мир, сущности в нём, кэш чанков, данные плагинов, куча JVM. Память определяет, сколько может существовать одновременно. У неё жёсткий край: ниже черты всё в порядке, выше - процесс убивают. Понятия «немного не хватает памяти» для контейнера с лимитом не существует: вы либо под лимитом, либо мертвы.
CPU выполняет работу. На каждом тике сервер продвигает симуляцию, и почти любой игровой движок делает это в одном потоке. CPU определяет, как быстро этот шаг завершается. У него мягкий край: по мере приближения к лимиту тики затягиваются, мир замедляется, и ничего не падает. Он деградирует, а не отказывает, и именно поэтому месяцами остаётся недиагностированным.
Есть и третий ресурс, который обычно относят к одному из этих двух по ошибке. Диск проявляется коротким зависанием по расписанию - сохранение мира, backup, ротация логов - и люди сообщают о нём как о лаге и покупают CPU. И четвёртый, сеть, проявляющийся тем, что одному игроку плохо, а всем остальным нормально.
Ещё одно различие, важное на любом хостинге с панелью. Показатель CPU в тарифе - это процент одного ядра: 100 - одно ядро, 250 - два с половиной. Это троттлинг, а не резерв и не гарантия того, какие именно физические ядра вы получите. На RE:NODE это жёсткий лимит: вашему контейнеру никогда не позволяют выйти за него, а сервер на 100% медленный, но не сломанный и за это никогда не приостанавливается. Для диагностики это важно: сервер, упёршийся в лимит CPU, не ведёт себя неправильно, он сообщает вам, что лимит - это лимит.
Как отличить их за тридцать секунд#
| Симптом | Почти наверняка | Не |
|---|---|---|
| Падает с «out of memory» в логе | Память | CPU |
| Сам перезапускается, в логе пусто | Память, убит снаружи | CPU |
| График памяти растёт до лимита и там ровно держится | Память | CPU |
| Память спокойна, время тика выше бюджета | CPU | Память |
| Хуже становится с ростом числа сущностей, а не игроков | CPU | Память |
| Короткое зависание раз в несколько минут, в остальное время нормально | Диск | Ни то, ни другое |
| Долгие паузы в случайные моменты, график памяти резко пилообразный | Сборка мусора | Чистый CPU |
| Затронут один игрок, у остальных всё хорошо | Сеть | Ни то, ни другое |
| Нормально при 10 игроках, невозможно играть при 40 | Обычно CPU | Иногда память |
Две строки люди путают чаще всего - вторую и четвёртую. Сервер, который перезапускается с пустым логом, почти всегда убивают из-за памяти: процесс не успевает оставить прощальную записку. А сервер, у которого график памяти ровный и спокойный, пока игроки жалуются, - это проблема CPU, каким бы соблазнительным ни казался тариф побольше.
Как правильно читать память#
Самая частая ошибка - путать память, которой, по мнению игры, она располагает, с памятью, которую ей даёт контейнер.
На сервере Java куча JVM задаётся через -Xmx, и куча - не весь процесс. Metaspace, стеки потоков, direct byte buffers, кэш кода JIT и собственные структуры сборщика мусора живут за её пределами. Укажите -Xmx4G в контейнере на 4 GB, и процесс превысит 4 GB и будет убит, а в логе игры ничего не окажется, потому что память кончилась не у игры, а у контейнера.
# Leave the JVM headroom. On a 6 GB plan:$ java -Xms5G -Xmx5G -XX:+UseG1GC -XX:+ParallelRefProcEnabled \ -XX:MaxGCPauseMillis=200 -XX:+AlwaysPreTouch -XX:+DisableExplicitGC \ -jar paper.jar noguiРазумное правило - -Xmx на уровне 80-85% лимита контейнера, с запасом минимум 512 MB и целым гигабайтом при модах. Если задать -Xms равным -Xmx вместе с -XX:+AlwaysPreTouch, куча занимается сразу, и график памяти выглядит тревожно ровным с первой минуты: это правильно и задумано, а не утечка. Остальные флаги разобраны в статье флаги JVM для Minecraft и версии Java, а аналогичная проблема для приложений Node, у которых свой отдельный потолок кучи, - в статье лимиты памяти узла простыми словами.
На машине, которую вы контролируете, улики лежат в трёх местах:
$ free -h # what the system has left$ dmesg -T | grep -i "killed process" # the kernel's own record of a kill$ journalctl -k | grep -i oom # same, on a systemd box# With cgroup v2, which is what a container limit actually is:$ cat /sys/fs/cgroup/memory.max # the limit, in bytes$ cat /sys/fs/cgroup/memory.current # what is in use right now$ cat /sys/fs/cgroup/memory.events # oom_kill counts, cumulativememory.events - то, что нужно знать. Если oom_kill больше нуля, что-то в этом контейнере убили из-за памяти, и теперь у вас факт, а не теория. Длинная версия - в статье swap в Linux и OOM killer.
Форма графика памяти подсказывает, какая именно у вас проблема с памятью:
- Растёт, затем ровно, заметно ниже лимита. Здоровое состояние. Так выглядит правильно подобранный сервер.
- Растёт до лимита и остаётся на нём. Либо куча, которой сказали занять всё, либо настоящая нехватка. Проверьте, не плохо ли и время тика; график, упёршийся в потолок при хорошем времени тика, - обычно просто
-Xms. - Пила, глубокая и частая. Сборка мусора работает на износ, потому что куча мала для рабочего набора. Это стоит CPU и проявляется рваным временем тика.
- Медленно растёт днями и не опускается. Утечка или мир, который действительно продолжает расти. Еженедельный перезапуск маскирует это; профилировщик находит.
Как правильно читать CPU#
Смотреть нужно не на «загрузку CPU», а на загрузку того потока, который важен, относительно купленного вами лимита.
$ top -H -p $(pgrep -f paper.jar) # per-thread, not per-process$ uptime # load average over 1, 5, 15 minutes$ vmstat 1 5 # r = runnable, st = stolen by the hypervisor# cgroup v2 again - this is the one that proves throttling:$ cat /sys/fs/cgroup/cpu.max # quota and period, e.g. "250000 100000"$ cat /sys/fs/cgroup/cpu.stat # nr_throttled, throttled_usecРост nr_throttled, пока сервер работает плохо, - неопровержимый признак: ваш контейнер снова и снова останавливают на квоте посреди тика. Так лимит CPU выглядит изнутри, и никакие настройки внутри игры его не снимают.
Здесь людей путают три вещи:
Выделение четырёх ядер при 25% загрузки всё равно может упираться в CPU. Если один поток загружен на 100% одного ядра, а три ядра простаивают, вид на уровне процесса покажет 25%. top -H показывает правду. Это нормальное состояние загруженного игрового сервера, потому что симуляция идёт в одном потоке.
Steal time - это не ваш CPU. Столбец st в vmstat - время, которое ваш виртуальный CPU хотел работать, а гипервизор отдал кому-то другому. Стабильно ненулевой steal означает, что хост перегружен, и никакая настройка с вашей стороны не поможет. Что тут можно сделать, описано в статье общий CPU и шумные соседи.
Load average - не процент. Нагрузка 4.0 на четырёхъядерной машине означает полную занятость; те же 4.0 на контейнере с одним ядром означают, что три задачи постоянно ждут. Читайте её относительно вашего выделения.
Какие игры вообще могут использовать больше одного ядра, полезно знать до того, как платить за ядра:
| Нагрузка | Дополнительные ядра используются для | Остаётся однопоточным |
|---|---|---|
| Minecraft (Paper) | Генерация чанков, сеть, ввод-вывод | Тик мира |
| Игры на движке Source | Очень мало | Весь игровой цикл |
| Серверы Unreal (Squad, Satisfactory) | Работа, близкая к рендерингу, и ввод-вывод | Физика и игровая логика |
| Factorio | Часть обновлений сущностей | Детерминированный шаг обновления |
| Приложение на Node или Python | Ничего, пока вы не запустите воркеры | Цикл событий |
| База данных | Действительно параллельно по соединениям | Один долгий запрос |
Закономерность такая: второе ядро стоит покупки, восьмое - обычно нет, а более высокая частота ценнее и того, и другого. Заметное исключение в Minecraft - форк Paper под названием Folia: он разбивает мир на независимо тикающие регионы и действительно масштабируется по ядрам, но ему нужны плагины, написанные под него, так что это выбор, который делают в начале проекта, а не исправление, применяемое к уже мучающемуся серверу.
Что делать, когда это память#
- Сначала сверьте `-Xmx` с лимитом контейнера. Больше серверов убивает неправильно настроенная куча, чем настоящая нехватка. Исправление бесплатно.
- Уменьшите то, что загружено. Понизьте
view-distanceиsimulation-distance, сократите границу мира, используйте предварительную генерацию вместо генерации на лету, уберите накопившиеся сущности. Каждый чанк, который вы не держите, - это память, которая вам не нужна. - Найдите утечку, прежде чем её кормить. Память, которая растёт бесконечно, - это плагин или мод. Профилировщик называет виновника за минуты; тариф побольше просто отодвигает срок.
- И только потом покупайте память. Это единственная проблема, которую тариф побольше действительно решает, чисто и навсегда.
Проблемы с памятью - в известном смысле хорошие: у них определённая причина, определённое решение, и решение масштабируется деньгами. Подбор объёма разобран в статьях сколько RAM нужно серверу Minecraft и сколько игроков помещается на сервере.
Что делать, когда это CPU#
Порядок здесь другой, потому что самое дешёвое решение почти никогда не железо.
- Найдите дорогую вещь. У большинства серверов, упирающихся в CPU, одна причина, а не общая нехватка: ферма мобов, плагин, работающий на каждом игровом тике, цепочка воронок, скрипт, выполняющий запрос к базе прямо в основном потоке. Сначала профилируйте - профилировщик spark для Minecraft, аналогичный инструмент вашей игры в остальных случаях.
- Делайте меньше работы за тик. Понизьте дальность симуляции, ограничьте число сущностей, увеличьте интервал всего запланированного, уберите неиспользуемые плагины. Здесь лежат самые большие выигрыши.
- Уберите блокирующую работу из основного потока. Синхронная запись на диск или встроенный вызов базы данных тратят бюджет тика впустую. Асинхронные сохранения и пулы соединений - это конфигурация, а не железо.
- Покупайте частоту, а не ядра. Если шаги с первого по третий исчерпаны, остаётся более быстрое ядро. Обычно это значит другая машина, а не более крупное выделение на той же: выделенные машины - там, где действительно указана модель CPU, а это единственный способ сравнить частоту до покупки.
- Смиритесь с меньшим числом игроков. Непопулярно, честно и иногда правильно.
Общий принцип: проблемы с памятью решаются покупкой, проблемы с CPU - сокращением работы. Сервер, упирающийся в CPU, при переходе на тариф побольше с тем же поколением процессоров получает чуть более высокий потолок и ту же проблему через месяц.
Разобранный пример#
Сервер Paper на тарифе 4 GB, 2 vCPU. Двадцать постоянных игроков, годовалый мир, каждый вечер жалобы на «лаг».
/mspt -> 48.6/312.4, 44.1/312.4, 29.8/486.0memory -> pinned at 3.9 GB of 4 GB all dayCPU -> 185% of an allowed 200%, all eveningПрочитайте три строки вместе. График памяти упёрся в потолок, и это выглядит ответом, - но куча была задана как -Xms3G -Xmx3G, так что, конечно, она упёрлась, а событий OOM нет. CPU занят на 92% выделения, и всю работу делает один поток. Среднее время тика - на границе бюджета в 50 мс, а максимальное - почти в десять раз выше.
Диагноз - CPU, плюс проблема со всплесками. Максимум в 486 мс - это отдельная проблема от среднего в 29,8 мс: что-то иногда занимает полсекунды, и обычно это генерация чанков у границы мира или автосохранение. Профилировщик нашёл настоящих виновников примерно за десять минут: view-distance=12 на сервере, где никто не смотрит дальше шести, и 3000 накопившихся сущностей-предметов в одной базе.
Исправление ничего не стоило. view-distance=8, simulation-distance=6, таймер исчезновения предметов, и среднее время тика упало до 18 мс. Тариф на 4 GB никогда не был проблемой. Если бы владелец купил 8 GB, график выглядел бы здоровее, а сервер ощущался бы точно так же.
Как купить то, что нужно#
| Вы наблюдаете | Покупайте | Не покупайте |
|---|---|---|
| OOM-убийства, куча настроена правильно | Больше памяти | Больше CPU |
| Время тика высокое, память спокойна | Частоту или делайте меньше работы | Больше памяти |
| CPU упирается только в часы пик | Больше доли CPU или проверьте steal | Больше памяти |
| Периодические зависания при сохранении | Более быстрое хранилище или более короткое сохранение | Ничего из вышеперечисленного |
| Жалуется один игрок | Ничего | Ничего |
| Всё нормально, мир всё ещё растёт | Пока ничего, но следите за памятью | Ничего |
Перед любой покупкой получите две точки данных с разницей в неделю, измеренные одинаково. О том, на что вы смотрите, рассказано в статье как читать график нагрузки сервера, о порогах, оправдывающих покупку, - в статье когда пора повышать тариф, а третий ресурс, который путают с первыми двумя, разобран в статье что на самом деле меняет NVMe. Если ответ окажется «целая машина», компромиссы описаны в статье выбор между VDS и игровой панелью.
FAQ#
Сделает ли больше RAM мой сервер быстрее?
Только если ему не хватало памяти. На сервере, у которого график памяти ровный, а время тика плохое, больше памяти не меняет ничего измеримого. Память поднимает потолок того, сколько может существовать; она не заставляет существующее обновляться быстрее.
Что на самом деле значит 2 vCPU?
Двести процентов одного ядра в виде троттлинга. Это не значит, что за вами зарезервированы два ядра, а поскольку большинство игровых серверов симулирует в одном потоке, один поток по-прежнему может использовать только 100% этого выделения. Второе ядро покрывает сеть, сохранения, сборку мусора и всё остальное вокруг симуляции.
Почему мой сервер всё время использует 100% CPU?
Потому что что-то постоянно просит работы, а лимит делает своё дело. На RE:NODE сервер на 100% медленный, но не в беде и никогда не приостанавливается за это. Спрашивать нужно, укладывается ли время тика в бюджет; если да, высокая загрузка CPU - просто эффективный сервер.
Хостинг говорит 8 GB, а Minecraft видит только 6. Почему?
Потому что -Xmx намеренно задан ниже лимита контейнера. JVM нужна память вне кучи для потоков, metaspace и буферов, а куча, равная всему контейнеру, приводит к убийству процесса. 6 GB кучи в контейнере на 8 GB - это правильно.
Всегда ли сбой без сообщения об ошибке - это память?
Не всегда, но ставить стоит на это. Процесс, убитый ядром за превышение лимита памяти, не имеет возможности ничего записать в лог. Проверьте счётчик OOM или лог ядра, прежде чем подозревать баг. Другие причины разобраны в статье почему ваш игровой сервер постоянно перезапускается.
Покупать больше ядер или более быстрое ядро?
Более быстрое ядро - почти для любой игры. Симуляция идёт в одном потоке, поэтому частота задаёт потолок, а лишние ядра помогают только с работой вокруг него. Два быстрых ядра лучше восьми медленных для игрового сервера, а для базы данных или сервера сборки верно обратное.




Комментарии
Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.