Minecraft-сервер лагает: находим и устраняем причины
Лагает сервер или соединение? Ощущается это одинаково, но причины совершенно разные: замер через TPS и Spark, предварительная генерация чанков, поиск виновника.
«Сервер лагает» — самое частое сообщение в тикет-системе любого оператора игровых серверов и одновременно самое бесполезное. За этой одной фразой скрываются как минимум три совершенно разные технические проблемы, которые не связаны друг с другом и устраняются совершенно разными средствами. Тот, кто здесь гадает вместо того чтобы измерять, неделями крутит view-distance и Java-флаги, пока настоящая причина — сломанная цепочка воронок в подвале у одного из игроков.
Эта статья идёт тем путём, который действительно работает: сначала различение, потом измерение, потом причина, потом мера противодействия. И в конце вопрос, который большинство руководств обходит стороной: по каким признакам вы поймёте, что проблема действительно устранена.
Две картины неисправности, которые ощущаются одинаково
Существует два принципиально разных вида подтормаживаний плюс третий случай, который к серверу вообще не имеет отношения.
Серверный лаг означает: сервер больше не успевает выполнять свои 20 расчётных шагов в секунду. Сам мир идёт медленнее. Мобы стоят на месте или дёргаются, печи работают дольше, сломанные блоки появляются снова, стойки для брони перемещаются с задержкой.
Сетевой лаг означает: сервер считает безупречно, но пакеты между игроком и сервером идут слишком долго или теряются. Игрока при беге откатывает назад (rubberbanding), удары не попадают, чат приходит с опозданием, а мобы вокруг при этом двигаются совершенно плавно.
Клиентский лаг — это третий случай: слишком мало кадров в секунду на компьютере игрока, чаще всего из-за шейдеров, большой дальности прорисовки в клиенте или недостаточно выделенной оперативной памяти. На сервере это не видно и там же не устраняется.
| Наблюдение | Серверный лаг | Сетевой лаг |
|---|---|---|
| Кто затронут | все игроки одновременно | отдельные игроки, часто из одного региона |
| Мобы поблизости | дёргаются, стоят, телепортируются | двигаются плавно |
| Пинг в меню Tab | обычный | высокий или скачущий |
| Консоль | «Can't keep up!» | тихо, возможны таймауты |
| Замер TPS | ниже 20 | ровно 20 |
| Момент проявления | воспроизводится под нагрузкой | часто вечером, зависит от времени суток |
Правило, которое почти всегда верно: если затронуты все одновременно, дело в сервере. Если отдельные игроки, дело в канале связи. Одно исключение ломает это правило: полностью перегруженный сервер подтверждает и сетевые пакеты с опозданием, а значит дополнительно порождает повышенные пинги. Поэтому измеряют всегда и то и другое.
Первая проверка занимает 60 секунд
Подключитесь к серверу по SSH и откройте консоль сервера. Если служба ещё не работает как положено в фоне, поможет статья Автоматический запуск Minecraft-сервера.
На Paper, Purpur и Folia начиная с 1.21 профилировщик Spark уже входит в состав сервера, устанавливать ничего не нужно. В игре или в консоли:
spark tps
spark health --memory --network
Вывод spark tps показывает четыре временных окна (5 секунд, 1, 5 и 15 минут), а также длительность тиков в виде минимума, медианы, 95-го перцентиля и максимума.
На чистом Vanilla без плагинов есть /tick query. Команда выдаёт целевую частоту и среднее время тика. Дополнительно F3 плюс 2 включает для операторов график тиков.
Консоль часто выдаёт проблему сама. Именно по этим строкам читатели обычно и ищут:
[Server thread/WARN]: Can't keep up! Is the server overloaded? Running 2123ms or 42 ticks behind
[Server thread/WARN]: Can't keep up! Did the system time change, or is the server overloaded? Running 2340ms behind
Это сообщение означает просто следующее: серверу потребовалось на один расчётный шаг заметно больше разрешённых 50 миллисекунд, и он вынужден пропускать тики. Одиночное сообщение после перезапуска или генерации мира — это норма. Одно такое каждые несколько минут — уже настоящая проблема.
Параллельно проверяем системную сторону. mpstat ни на одной из проверенных систем не входит в базовый набор, он идёт из пакета sysstat и его нужно один раз доустановить:
apt-get install -y sysstat procps
uptime
free -h
mpstat 1 3
На AlmaLinux, Rocky Linux и Oracle Linux первая строка выглядит как dnf -y install sysstat procps-ng iproute, там пакет с free, uptime, top и vmstat называется не procps, а procps-ng.
В выводе mpstat интересна прежде всего колонка %steal. Значения, постоянно превышающие 5 процентов, означают, что виртуальная машина ждёт процессорного времени, занятого другим гостем. Тогда это не проблема Minecraft, а проблема ёмкости нижележащего оборудования.
Оговорка к этим трём командам: на собственном сервере или VPS они показывают ровно то, что вы хотите узнать. Если же ваш сервер работает в контейнере, например в игровой панели вроде Pterodactyl, то free, uptime, vmstat и mpstat сообщают значения хост-системы, а не вашего экземпляра. Вы увидите чужую нагрузку и чужую память. В этом случае полагайтесь на показания панели и на spark health.
Как правильно читать TPS и MSPT
Сервер Minecraft считает 20 тиков в секунду, то есть у каждого тика бюджет в 50 миллисекунд. MSPT (миллисекунды на тик) — более показательное значение, потому что оно вскрывает проблемы ещё до того, как TPS вообще начнут падать. Сервер с 20,0 TPS и 46 мс MSPT работает на самом пределе и заваливается на следующем же игроке, который зайдёт в новую область.
- MSPT ниже 30 мс: здоровое состояние, запас есть.
- MSPT от 30 до 45 мс: тесно, но играбельно. Действовать нужно уже сейчас.
- MSPT выше 50 мс: TPS падают неизбежно, игроки это замечают.
Важнее среднего значения распределение. Медиана 18 мс при максимуме 900 мс означает всплески: отдельные дорогие события вроде автосохранения, генерации чанков или плагинной задачи раз в минуту. Медиана 60 мс, наоборот, означает постоянную нагрузку, то есть слишком много тикающего содержимого для имеющейся вычислительной мощности. Меры противодействия здесь совершенно разные.
Момент, который консультанты по железу охотно обходят: основной тик Minecraft выполняется в одном-единственном потоке. Загрузка чанков и сеть вынесены отдельно, а сама симуляция мира нет. Сервер с 32 ядрами и слабой производительностью одного ядра для Minecraft медленнее, чем сервер с 8 быстрыми ядрами. Дополнительные ядра начинают помогать лишь тогда, когда на машине работает несколько экземпляров сервера.
Spark: от подозрения к доказательству
Timings, многолетний стандартный инструмент, в Paper начиная с ветки 1.21 переведён в холостой режим и полезных данных больше не даёт. Кто сегодня всё ещё выкладывает ссылки на Timings, тот не измеряет ничего. Преемника зовут Spark, в Paper он встроен, для Fabric, Forge и NeoForge есть в виде мода, для Velocity и BungeeCord отдельной сборкой.
Решающий момент в подходе: профилируйте тогда, когда проблема происходит. Профиль пустого сервера в три часа ночи бесполезен.
spark profiler start --timeout 300
spark profiler stop
Для всплесков, которые возникают лишь время от времени, целенаправленно отфильтровывают плохие тики:
spark profiler start --only-ticks-over 60 --timeout 600
Так записываются только те тики, которые длились дольше 60 миллисекунд. Именно их игроки и чувствуют. Остальное игнорируется и не зашумляет картину.
При чтении флеймграфа новички почти всегда делают одну и ту же ошибку: смотрят на самое глубокое ветвление. Правильно же смотреть на ширину полос непосредственно под серверным тиком. Запись с 3 процентами не имеет значения, даже если она уходит на сто уровней вглубь. Практическое правило: отдельный плагин с долей более 15 процентов времени тика уже кандидат. Очень широкие записи вокруг блок-сущностей указывают на редстоун и воронки, широкие записи вокруг загрузки чанков на генерацию мира.
Замечание о конфиденциальности: загруженный отчёт доступен публично по своей ссылке и содержит сведения о системе, пути, параметры запуска и полный список плагинов. Передавайте ссылку только тем людям, которым вы доверили бы эту информацию. С ключом --save-to-file профиль остаётся локальным.
Типичные виновники
Редстоун и фермы
Воронки с большим отрывом самые дорогие блоки в игре, потому что каждая из них на каждом тике проверяет, не лежит ли что-нибудь сверху. Сортировочная система из 400 воронок стоит больше процессорного времени, чем сотня мобов. К этому добавляются часы на наблюдателях, которые работают и тогда, когда рядом никого нет, если чанк симулируется. Если Spark тратит подозрительно много времени в блок-сущностях, ищите именно такие механизмы.
Сущности
На Paper команда /paper entity list перечисляет сущности по мирам и типам вместе с координатами чанков. Это самый быстрый путь к проблемной области. Типичные находки: несколько тысяч стопок предметов в мобоферме, загон для разведения с 300 коровами, забытый участок, заваленный выпущенными стрелами.
Разумные меры в spigot.yml: снизить entity-activation-range для животных и монстров (скажем, животных с 32 до 16, монстров с 32 до 24) и слегка поднять merge-radius для предметов и шаров опыта, чтобы отдельных объектов существовало меньше. В paper-world-defaults.yml параметр entity-per-chunk-save-limit ограничивает, сколько объектов одного типа вообще сохраняется на чанк.
Загрузка чанков
Игрок с элитрами или на быстрой лошади заставляет сервер постоянно порождать новую местность. Генерация мира вообще самая дорогая одиночная операция. То же самое происходит при первом входе в Нижний мир или после расширения границы мира. Решение здесь не значение в конфигурации, а предварительная генерация, и она достаточно важна, чтобы отвести ей отдельный раздел ниже.
Плагины
Если Spark указывает на плагин, вопрос закрыт. Если нет, помогает только поиск делением пополам: отключить половину плагинов, измерить, затем в зависимости от результата делить пополам нагруженную половину дальше. При 32 плагинах это пять перезапусков вместо 32. Перед этим обязательно резервная копия, потому что плагины, пишущие данные мира, при удалении могут оставить содержимое, которое без них больше не работает.
Предварительная генерация чанков до того, как по ним пробегут игроки
Это самая действенная отдельная мера во всей статье, и её же чаще всего упускают из виду. Причина в том, как устроен Minecraft: загрузить уже созданный чанк с накопителя почти ничего не стоит. А вот создать новый чанк означает карту высот, биомы, распределение руд, пещеры, структуры и расчёт освещения, и большая часть этого выполняется в главном потоке. Ровно там, где должны рождаться и 20 тиков в секунду.
Поэтому подтормаживания начинаются обычно тогда, когда кто-то улетает на элитрах или строит железную дорогу в неизвестность: сервер порождает мир и одновременно должен считать игру. Тот, кто один раз заранее сгенерирует мир до его границы, превращает дорогую вычислительную работу в дешёвое чтение с накопителя.
Chunky, инструмент первого выбора
Chunky это общеупотребительный сегодня предгенератор, он работает как плагин на Paper, Spigot и Purpur, а также как мод на Fabric и Forge. Порядок действий на всех платформах одинаков:
/chunky world world
/chunky center 0 0
/chunky radius 5000
/chunky start
Радиус задаётся в блоках и должен соответствовать границе мира. О прогрессе и оценке оставшегося времени Chunky сообщает сам; командами /chunky pause и /chunky continue проход можно в любой момент остановить и продолжить, в том числе после перезагрузки.
Нижний мир и Край это отдельные миры, их нужно предгенерировать по отдельности. На Paper и Spigot они по умолчанию называются так:
/chunky world world_nether
/chunky radius 1000
/chunky start
Для Нижнего мира достаточно радиуса поменьше, потому что там один блок соответствует восьми блокам верхнего мира. Радиус 1000 в Нижнем мире покрывает, таким образом, 8000 блоков верхнего мира.
Что при этом нужно заложить в план
- Время. Радиус 5000 блоков это около 78 миллионов блоков площади. В зависимости от железа, модпака и генератора мира это занимает от часа до нескольких суток. Модпаки с собственными генераторами мира заметно медленнее Vanilla.
- Дисковое пространство. Предварительно сгенерированный мир быстро занимает несколько гигабайт. Проверьте заранее, сколько места свободно, иначе накопитель заполнится прямо во время прохода, а это ударит по серверу сильнее любых подтормаживаний. Как это проверить и убрать лишнее, описано в статье Диск заполнен: как найти и освободить место.
- Момент. Предгенерируйте на пустом сервере, а не во время работы. Во время прохода частота тиков ожидаемо плохая, это не ошибка. Весь смысл как раз в том, чтобы вынести эту нагрузку из игрового времени.
- Задать границу мира. Без границы рано или поздно кто-нибудь выйдет за предгенерированную область и всё начнётся заново. Установите границу на тот же радиус, который вы предгенерировали.
Уборка задним числом
Если мир уже разросся и содержит области, куда больше никто не заходит, Chunky удаляет чанки за пределами границы мира:
/chunky trim
Это ощутимо уменьшает мир, а вместе с ним и резервные копии. Обязательно сделайте резервную копию заранее, потому что удалённые чанки при следующем посещении создаются заново, и всё, что игроки там построили, будет потеряно.
Если Chunky не подходит
На старых серверах часто ещё встречается WorldBorder с /wb fill. Он выполняет ту же задачу, но проект уже много лет почти не сопровождается, и для актуальных версий сервера Chunky надёжнее. В обоих случаях перед установкой проверьте, действительно ли предлагаемая сборка подходит к вашей версии сервера.
view-distance и simulation-distance
Эти два значения в server.properties постоянно путают.
view-distanceопределяет, насколько далеко чанки отправляются клиенту. Стоит пропускной способности и немного памяти.simulation-distanceопределяет, насколько далеко сервер рассчитывает сущности, редстоун и обновления блоков. Стоит процессорного времени в главном тике.
Чанки между границей симуляции и границей прорисовки отображаются, но на стороне сервера заморожены. Затраты растут квадратично: при view-distance=10 это 21 на 21, то есть 441 чанк на игрока.
Проверенные стартовые значения для survival-сети на 10-30 игроков:
view-distance=8
simulation-distance=5
Тем, кто ещё находит руководства с no-tick-view-distance: эта опция Paper устарела. Mojang в версии 1.18 ввёл simulation-distance и тем самым решил ту же задачу официально. Кто задаёт старое значение сегодня, не добивается ничего.
Цена низких значений называется редко: при simulation-distance ниже 4 разваливаются AFK-фермы, спавн мобов ведёт себя иначе, печи в соседнем чанке перестают работать, а редстоун-часы останавливаются. У кого сообщество завязано на фермы, тот экономит здесь не в том месте и меняет техническую проблему на игровую. Двигайтесь шагом в единицу и измеряйте после каждого шага.
Уборка без разрушения мира
Любое вмешательство в данные мира начинается с резервной копии при остановленном сервере. Без компромиссов, без исключений:
tar -czf world-backup.tar.gz world world_nether world_the_end
После этого стоит взглянуть на размер данных регионов:
du -sh world/region
Миры, разраставшиеся годами, часто содержат сотни мегабайт местности, над которой один-единственный игрок однажды пролетел. Эти чанки не стоят времени тика, зато занимают место на накопителе и удлиняют каждое сохранение. Если места становится мало, дополнительно поможет статья Как освободить место на диске в Linux.
Регулярные всплески в районе секунды, возникающие ровно каждые пять минут, почти всегда оказываются автосохранением. В bukkit.yml интервал задаёт ticks-per.autosave, а в paper-world-defaults.yml параметр max-auto-save-chunks-per-tick ограничивает, сколько пишется за тик. Меньшее значение распределяет нагрузку вместо того, чтобы собирать её в один момент.
Для небольших частных серверов начиная с ветки 1.21 в server.properties есть опция pause-when-empty-seconds. Если там стоит значение больше нуля, сервер по истечении этого времени без игроков перестаёт тикать мир. На общем root-сервере это ощутимо экономит вычислительное время.
Когда тормозит JVM
Если среднее время тика остаётся низким, но нерегулярно подскакивает до нескольких сотен миллисекунд, часто виновата сборка мусора среды выполнения Java. Проверить это можно напрямую:
spark gcmonitor
spark heapsummary
Два распространённых заблуждения: больший heap не означает автоматически лучше, потому что большие heap-области дают более длинные паузы при сборке мусора. И heap ни в коем случае нельзя выбирать настолько большим, чтобы операционную систему вытеснило в swap. Свопящий сервер Minecraft безнадёжно медленный. Проверьте это командой vmstat 1 5: постоянные значения в колонках si и so это приговор. Предыстория в статье Настройка swap и защита от Out of Memory.
Это сообщение — симптом, а не причина:
java.lang.OutOfMemoryError: Java heap space
Увеличение heap лишь отодвигает падение, если плагин течёт по памяти или существуют миллионы сущностей.
По версии Java дистрибутивы заметно расходятся, и именно на этом спотыкается множество установок. Начиная с Minecraft 1.20.5 требуется Java 21. Debian 12 в стандартном репозитории даёт только OpenJDK 17 и не даёт OpenJDK 21, Debian 13 даёт 21 и 25, но не 17. У Ubuntu 22.04 и 24.04 в репозитории есть и 17, и 21. Кому нужно остаться на Debian 12, тот ставит Temurin из репозитория Adoptium. Шаги описаны в статье Установка Java 21 на Debian, для более старых версий сервера в статье Установка Java 17 на Debian.
Не хватайтесь при этом за удобный сборный пакет default-jre-headless. В зависимости от релиза он указывает на совершенно разные версии: Debian 13 и Ubuntu 24.04 дают с ним Java 21, Debian 12 даёт Java 17, Debian 11 и Ubuntu 22.04 дают Java 11. Установка везде проходит без ошибок, но на двух последних сервер всё равно не запускается. Поэтому называйте версию явно, то есть openjdk-21-jre-headless.
java -version
java -XX:+PrintFlagsFinal -version 2>/dev/null | grep -w MaxHeapSize
Конструкция 2>/dev/null подавляет баннер версии, который JVM пишет в поток ошибок и который иначе оказался бы посреди вывода. А grep -w MaxHeapSize выдаёт ровно одну строку, тогда как нестрогий поиск нашёл бы дополнительно SoftMaxHeapSize.
Если что-то пошло не так и как вернуться назад
Сервер аварийно завершается с ошибкой watchdog. В логе тогда написано по смыслу, что отдельный тик длился 60 секунд и сервер считается упавшим. Это не сбой, а защитная мера против намертво зависшего процесса. Приложенный stacktrace на вес золота: он показывает точно, на чём сервер застрял. Порог задаёт значение max-tick-time в server.properties. Его отключение ничего не исправляет, оно лишь превращает падение в навсегда замерший сервер.
После изменения конфигурации стало хуже. Именно поэтому действует главное правило этой диагностики: всегда только одно изменение на один замер, и исходное значение записать. Кто трогает view-distance, диапазоны сущностей и Java-флаги одновременно, тот потом не знает, что именно сработало.
После падения сервер больше не запускается. Чаще всего повреждён level.dat. В папке мира лежит level.dat_old, который можно скопировать поверх, предварительно сохранив копию сломанного состояния. При повреждённых файлах регионов поможет только резервная копия.
Всё оптимизировано, а подтормаживания остались. Тогда проверьте уровень ниже: %steal в mpstat, выгрузку в swap в vmstat и задержку накопителя. Если время тика остаётся высоким, хотя Spark не показывает ни одного отдельного виновника выше 10 процентов, значит содержимого просто слишком много для такой производительности одного ядра. Тогда поможет разделение на несколько экземпляров или больше вычислительной мощности, а не следующий винтик в конфигурации.
Высокие пинги только у игроков, а сервер спокоен. Тогда дело в сети. Локация с короткими маршрутами до игроков даёт здесь наибольшую разницу. Для серверов во Франкфурте-на-Майне типичные задержки из немецкоязычного региона лежат в нижнем двузначном диапазоне. Если сбои возникают внезапно и пачкой, за этим может стоять и атака, см. Как защитить сервер от DDoS-атак. На стороне клиента тогда появляются сообщения такого рода:
Internal Exception: io.netty.handler.timeout.ReadTimeoutException
Timed out
Connection reset
По каким признакам понятно, что проблема действительно устранена
Исправление считается подтверждённым только тогда, когда оно выдерживает ровно ту нагрузку, при которой проблема возникала. Ночью при двух игроках ровно работает и сломанный сервер. Проверяйте в часы пик:
spark tpsпоказывает 20,0 в 15-минутном окне, а не только в 5-секундном.- 95-й перцентиль времени тика лежит ниже 40 мс, максимум ниже 100 мс.
- 24 часа лога без единой строки «Can't keep up!».
- Свежий профиль Spark больше не показывает ни одной отдельной позиции выше 15 процентов.
spark gcmonitorне сообщает о паузах длиннее 200 мс.- Игроки, которые обращались, подтверждают улучшение в том же месте и в той же игровой ситуации.
Запишите значения до и после, в идеале с датой и с тем изменением, которое было внесено. При следующем провале через три месяца этот список окажется ценнее любого руководства, потому что он показывает, что уже срабатывало именно на вашем сервере. Кто настраивает сервер заново, найдёт нужную основу в статьях Установка Minecraft-сервера на Debian и Чек-лист по настройке нового root-сервера.
Частые вопросы
Как понять, лагает сервер или моё интернет-соединение?
Что означает сообщение Can't keep up! Is the server overloaded?
Нужно ли до сих пор устанавливать Spark как плагин?
Какие значения view-distance и simulation-distance имеют смысл?
Помогает ли больше оперативной памяти против низких TPS?
Почему процессор с большим числом ядер мало даёт в Minecraft?
Действительно ли предварительная генерация чанков помогает от лагов?
2026 KernelHost GmbH. Все права защищены. Эта инструкция охраняется авторским правом. Публикация на других сайтах, в том числе частично или в изменённом виде, без нашего письменного согласия не разрешается. Цитирование с указанием источника и активной ссылкой мы приветствуем.

