Лаг на сервере Minecraft - это проблема бюджета. На каждый тик отведено пятьдесят миллисекунд, чтобы просимулировать весь мир, и когда работа не помещается, тик затягивается, а часы отстают. spark нужен, чтобы по именам сказать, куда ушли эти пятьдесят миллисекунд: этот плагин, этот метод, этот тип сущностей, эта загрузка чанка. Десять минут с профилировщиком лучше недели отключения плагинов по одному, и спор он заканчивает ссылкой, а не мнением. Дальше - как снять отчёт, который стоит читать, и как его прочитать.
Важен MSPT, а не TPS#
TPS - тики в секунду - число, которое цитируют все, и из двух оно менее полезно. Оно ограничено 20, потому что сервер никогда не побежит быстрее часов игры. MSPT, миллисекунды на тик, - это настоящее измерение: сколько заняла работа в тике. Связь простая. Пока MSPT остаётся ниже 50, TPS показывает 20.0. Как только MSPT переходит через 50, TPS падает пропорционально.
Именно из-за этого потолка TPS прячет самое интересное. Сервер с 20.0 TPS и средним MSPT 45 не здоров: он в одной большой ферме, одном новом плагине или одной загруженной субботе от провала, а ощущаться будет хуже, чем говорит число, потому что пики уже выше 50, даже если среднее - нет.
| Показание | Что это значит |
|---|---|
| TPS 20.0, MSPT 12 | Здоров. Большой запас |
| TPS 20.0, MSPT 45 | Полная скорость, запаса нет |
| TPS 18.5, MSPT 54 | Тики выбиваются из времени. Примерно на 8% медленнее реального времени |
| TPS 20.0 в среднем, MSPT max 300 | Пики. Среднее вам лжёт |
Средние - вторая ловушка. Игроки не замечают среднего, они замечают момент, когда сервер замирает на треть секунды, пока в главном потоке грузится чанк. Поэтому смотрите на максимум и на распределение, а не только на среднее, и делите отчёт на два отдельных вопроса: сервер стабильно превышает бюджет или в порядке всё, кроме пиков? От ответа зависит, за какой инструмент браться. Почему фиксированный тик делает всё так беспощадным, подробнее рассказано в статье что на самом деле означает tick rate.
Ещё одно различие полезно провести сразу. Лаг на стороне сервера заставляет всех подтормаживать одновременно, блоки ломаются и появляются снова, а мобы телепортируются. Лаг на стороне клиента или плохой маршрут между одним игроком и сервером затрагивает одного человека, пока у остальных всё нормально. spark измеряет сервер. Если TPS равен 20.0, MSPT равен 15, а кто-то всё равно жалуется, вы смотрите не туда - прочтите вместо этого задержка, джиттер и потеря пакетов.
Установка spark и три команды перед профилированием#
spark - это один jar в plugins/ на Paper и Spigot и мод в mods/ на Fabric, Forge и NeoForge. Он работает и на Velocity, и на BungeeCord, где профилирует прокси, а не бэкенд. Некоторое серверное ПО теперь поставляется с ним уже внутри, поэтому перед загрузкой чего-либо введите /spark в консоли. Если в ответ придёт справка, он уже есть.
Командам нужны права оператора или право spark, а у консоли оно есть всегда. Сэмплирование асинхронно и дёшево - малые единицы процента одного ядра на обычном сервере, - но оно не бесплатно, и оставлять его работать на неделю не стоит.
Перед снятием профиля составьте картину формы проблемы:
$ spark tps$ spark health --memory$ spark tickmonitor --threshold 200Каждая из них отвечает на свой вопрос.
/spark tpsпечатает TPS за несколько окон (от 5 секунд до 15 минут), MSPT за последние 10 секунд и за последнюю минуту и - то, что упускают, - загрузку CPU и системы, и процесса этого сервера. В контейнере с жёстким лимитом CPU процесс, упёршийся в свою долю, и есть весь диагноз: сервер не ждёт медленный плагин, он ждёт ядро. Сервер на 100% своей доли медленный, но не сломан./spark health --memoryдобавляет использование кучи, статистику сборки мусора и место на диске. Она отвечает на вопрос «это проблема памяти?» одним экраном./spark tickmonitor --threshold 200печатает строку для каждого тика, который длится больше чем вдвое дольше среднего. Оставьте его на несколько минут, и вы узнаете, регулярны ли пики (запланированная задача, автосохранение) или связаны с чем-то, что сделал игрок.
Вместе эти три ответа определяют, какой профиль снимать дальше. Постоянному перерасходу нужен длинный простой профиль. Пикам - отфильтрованный.
Как снять профиль, который стоит читать#
Для постоянной проблемы подходит вариант по умолчанию:
$ spark profiler start --timeout 300Он сэмплирует главный поток сервера пять минут, а затем останавливается сам, и это лучше, чем запустить и забыть. Пять минут с игроками онлайн лучше тридцати секунд на пустом сервере: в отчёт может попасть только работа, происходившая, пока он шёл, поэтому профилируйте сервер в том состоянии, на которое жалуются.
Флаги, меняющие ответ:
| Флаг | Что делает |
|---|---|
--timeout <seconds> | Автоматически остановиться через это время |
--thread <name> | Профилировать поток с этим именем вместо главного |
--thread * | Профилировать все потоки |
--only-ticks-over <ms> | Записывать только тики, длиннее этого значения |
--interval <ms> | Интервал сэмплирования, по умолчанию около 4 мс |
--alloc | Профилировать выделение памяти вместо процессорного времени |
--only-ticks-over - тот, что окупает себя. Отчёт, построенный по всем тикам, забит обычной работой, которую сервер выполняет 20 раз в секунду, а интересующая вас заморозка в 300 мс - это 0,5% сэмплов. Запустите заново как /spark profiler start --only-ticks-over 100 --timeout 600, и в отчёте не будет ничего, кроме плохих тиков, поэтому то, что их вызвало, внезапно оказывается наверху.
Используйте --thread *, когда главный поток выглядит невиновным: генерация и сохранение чанков и асинхронные задачи плагинов живут в других потоках, а плагин, выполняющий «фоновую» работу с частыми обращениями к диску, нигде больше не проявится. Используйте --alloc, когда память быстро растёт, а сборка мусора - видимый симптом, потому что такой отчёт называет код, создающий объекты, а не код, использующий процессор.
Когда профиль остановится, spark загружает его и печатает ссылку на свой веб-просмотрщик. Выполните /spark profiler без аргументов, чтобы узнать, поддерживает ли ваша сборка сохранение в файл, - полезно знать, если названия плагинов и миров в отчёте вы предпочли бы не публиковать. Ссылка скрыта от списков, но не засекречена.
Чтение отчёта: Sources, Flat и дерево вызовов#
Просмотрщик открывается на дереве вызовов, которое хуже всего подходит для начала. Переключайте виды в таком порядке.
Sources относит время к плагину или моду, откуда оно пришло. Это вид, отвечающий на тот вопрос, который у вас на самом деле есть. Он объединяет всё, что делает плагин - его обработчики событий, его запланированные задачи, работу, которую он вызывает внутри сервера, - в один процент. Если у одного плагина 35% главного потока, вы закончили; идите читать его конфигурацию. Если на первом месте «Minecraft» или сам сервер, то ни один плагин не виноват, а проблема в мире.
Flat сортирует методы по собственному времени: сколько времени потрачено внутри самого метода, а не в том, что он вызвал. Так находится конкретный горячий цикл. Здесь вы узнаёте, что стоимость - не «сущности» вообще, а поиск пути, или не «плагин магазина», а один запрос к базе данных.
All - полное дерево, и открывать его стоит, когда у вас уже есть подозреваемый, потому что оно показывает путь, которым работа туда попала. Слушатель плагина, стоящий под ванильным методом, говорит, что плагин реагирует на то, что мир делает часто, а это другое исправление, чем когда плагин делает своё по таймеру.
Две привычки делают отчёты читаемыми. Во-первых, современный Paper работает с собственными маппингами Mojang, поэтому классы выглядят как ServerLevel и HopperBlockEntity, а не как обфусцированные aab.a(), которые вы получаете на старых сборках Spigot, - если ваш отчёт превратился в стену двухбуквенных имён классов, причина в этом. Во-вторых, проценты в отчёте - это проценты окна профилирования, а не бюджета тика. Сорок процентов потока, который был занят всего на 30%, - не чрезвычайная ситуация.
Пять вещей, которые отчёт обычно называет#
Почти любой отчёт на обычном выживательном сервере упирается в одно из этого.
- Тики сущностей. Ищите
ServerLevel.tickNonPassengerс классами мобов и методами целей и навигации под ним. Это ферма мобов, чанк, набитый жителями, или несколько сотен предметов на полу. Дорогая часть - поиск пути, и хуже всего он в тесных пространствах, где моб не может найти маршрут. - Загрузка чанков в главном потоке. Местность, которую никогда не генерировали, генерируется, когда кто-то заходит в неё, и хотя Paper выносит большую часть этой работы из тика, загрузка и освещение всё равно стоят времени. Признак - пики, следующие за игроком, а не постоянная нагрузка, нередко когда кто-то летит на элитрах или соединяется новый портал в Незер. В свежем Paper
/paper syncloadinfoназывает то, что принуждает чанк загружаться синхронно, и это часто плагин. - Блочные сущности. Воронки тикают, двигается что-то или нет, и стена из них с пустым содержимым всё равно стоит времени.
HopperBlockEntityв верхней части вида Flat означает, что систему хранения нужно перепроектировать или ограничить. - Редстоун. Большие часы и механизмы с обилием обновлений проявляются как методы обновления соседей и проводов. Ферма одного игрока может отнимать десятую часть бюджета.
- Блокирующая работа внутри плагина. Худшая находка и самая простая для исправления. Чтение из сокета, чтение файла или веб-запрос под обработчиком событий плагина означают, что весь сервер остановился, пока этот вызов ждал. Классика - плагины экономики и статистики, делающие запрос при входе. В игре всё в порядке; неправ плагин.
Если отчёт называет плагин, который вы не можете изменить, вы всё равно кое-что выигрываете: ссылка на отчёт - ровно то, что нужно автору, чтобы это исправить, и она куда убедительнее, чем «ваш плагин лагает».
Память, сборка мусора и сводки кучи#
Проблемы с памятью выглядят как лаг, но вызваны не медленным кодом. Признак - регулярные пики без очевидного источника плюс время сборки мусора в отчёте о состоянии.
$ spark health --memory$ spark gcmonitor$ spark heapsummary/spark gcmonitor печатает каждую сборку в момент её выполнения. Короткие паузы молодого поколения, от единиц до низких десятков миллисекунд, нормальны и неизбежны. Повторяющиеся долгие паузы или куча, стоящая у потолка и не уменьшающаяся после сборки, означают, что куча мала для мира либо что-то удерживает ссылки, которые не должно. /spark heapsummary перечисляет живые объекты по классам с количеством, и именно так выясняется, что настоящая проблема - 400 000 выброшенных предметов или плагин, накапливающий по объекту на каждый поставленный с прошлого перезапуска блок.
Контринтуитивная часть: большая куча не обязательно лучше. Очень большая куча удлиняет каждую сборку и скрывает утечку, а не обнажает её. Подберите кучу под мир и список плагинов, задайте минимум равным максимуму и оставьте запас за пределами кучи для самой JVM - числа даны в статье флаги JVM и версии Java для Minecraft, а подбор объёма - в статье сколько RAM нужно серверу Minecraft. Помните, что лимит памяти контейнера относится ко всему процессу, а не только к куче, поэтому -Xmx, равный памяти вашего тарифа, - вот как серверы оказываются остановленными.
Как найти чанк или сущность за цифрами#
Отчёт говорит «тики сущностей занимают 30% вашего тика». Он не говорит «на x 1180, z -2044». Разрыв закрывают собственные команды Paper:
$ paper entity list$ paper mobcaps$ minecraft:debug start$ minecraft:debug stop/paper entity list печатает количество сущностей по типам с координатами чанков, так что можно отсортировать по худшему чанку и пойти посмотреть. Точный синтаксис и фильтры зависят от версии Paper, поэтому сначала выполните команду без аргументов. /paper mobcaps показывает, насколько каждая категория спавна близка к своему пределу, и это говорит, не держит ли ферма в заложниках естественный лимит спавна для всего сервера.
Ванильный профилировщик тоже на месте. /minecraft:debug start и /minecraft:debug stop записывают в папку debug отчёт с таймингами по тикам, разбитыми по внутренним разделам игры, и это лучший инструмент для серверов с датапаками и обилием команд, потому что он относит время к функциям. Обратите внимание на префикс minecraft:: на сервере на основе Bukkit простое /debug может разрешиться во что-то совсем другое.
Когда вы знаете чанк, исправление обычно физическое. Ограничьте ферму, уберите накопившиеся предметы, ужмите цепочку воронок или попросите игрока перестроить её. Удаление сущностей грубой командой «убрать всё» работает и раздражает людей, поэтому предупредите их заранее.
Что менять и в каком порядке#
Сначала самое дешёвое, и замеряйте после каждого шага, а не меняйте пять вещей и не объявляйте победу.
- Уберите найденное скопление и ограничьте то, что его породило. Предметы на полу - проблема дизайна, а не хостинга.
- Уменьшите
view-distance, а затемsimulation-distanceна один-два вserver.properties. Игроки не заметят; сервер заметит. Это самое ценное изменение на большинстве небольших серверов, подробно оно разобрано в руководстве по оптимизации Paper. - Исправьте или уберите плагин, названный отчётом. Сначала конфигурация - у большинства тяжёлых плагинов есть интервал сканирования или радиус, которые можно уменьшить, - затем удаление.
- Заранее сгенерируйте мир и задайте границу, чтобы исследование не генерировало местность прямо во время игры. См. граница мира и предварительная генерация.
- Добавьте расписание перезапусков, если и только если память или MSPT растут днями, а не минутами. Разницу между полезным перезапуском и суеверием объясняет статья расписания перезапусков, которые помогают.
- И только потом покупайте больше CPU. Это самое дорогое исправление и то, которое меньше всего поможет, если ответом был плагин, потому что главный цикл игры однопоточный и не распределяется по ядрам.
После изменения снимите второй профиль в тех же условиях и сравните. Два отчёта - это результат. Один отчёт плюс ощущение - это рассказ. Те же исправления, ранжированные по тому, во что они обходятся вам в геймплее, - в статье почему падает TPS и что делать.
FAQ#
Вызывает ли spark сам лаг?
Почти нет. Сэмплирование асинхронно, а накладные расходы - несколько процентов одного ядра, пока идёт профиль, и это меньше того, за чем вы охотитесь. Оставлять профиль работать бесконечно - всё равно дурная привычка: остановите его или запускайте с --timeout.
TPS равен 20, но сервер всё равно ощущается плохо. Что делать?
Смотрите на максимальный MSPT, а не на среднее, и запустите /spark tickmonitor. Сервер, у которого в среднем 20 мс и который дважды в минуту подскакивает до 400 мс, выглядит идеальным и плохо играется. Если MSPT действительно ровный и низкий, проблема в сетевом пути или в клиенте, а не в сервере.
spark лучше, чем Timings?
Он отвечает на больше вопросов. Timings говорил, какие обработчики дороги; spark профилирует настоящую JVM, поэтому видит ещё и сборку мусора, блокирующие вызовы, работу в других потоках и внутренности ванили. Собственные рекомендации Paper перешли на spark, и Timings больше не рекомендуемый инструмент.
Какой MSPT нормален для небольшого выживательного сервера?
С горсткой игроков, заранее сгенерированным миром и коротким списком плагинов типичны 5-20 мс. Тридцать-сорок - загруженный сервер, который всё ещё работает. Всё, что стабильно выше 50, отстаёт от реального времени, и игроки это чувствуют.
Можно ли профилировать сеть прокси?
Да, но профилируйте правильный процесс. spark на Velocity или BungeeCord измеряет прокси, который почти никогда не является причиной лагов тика, потому что не симулирует мир. Профилируйте бэкенд, на котором были игроки, когда это тормозило. Как всё это устроено, рассказано в статье сети прокси на Velocity.
Почему память продолжает расти, даже когда TPS в порядке?
До определённого предела это нормально: больше загруженных чанков и больше исследованного мира - больше нужно держать. Ненормальна куча, которая никогда не уменьшается после сборки. Выполните /spark heapsummary и посмотрите, у какого класса неправдоподобное число экземпляров.




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