Классическая ситуация: TPS падает до 14, в чате жалобы, а вы по очереди выключаете плагины и надеетесь угадать. Spark — профайлер Minecraft, который убирает угадывание совсем: он показывает, сколько миллисекунд каждого тика уходит в конкретный метод конкретного плагина или в ванильную механику.
Ставится за минуту, работает на Paper, Fabric, Forge и на прокси, а отчёт открывается в браузере обычной ссылкой. Дальше — как им пользоваться на практике.
Установка
Начиная с версии 1.21 Paper поставляется со встроенным Spark — ставить ничего не нужно, это предпочтительный способ профилирования по документации PaperMC. Для Spigot, старых версий, Fabric и Forge скачайте сборку под своё ядро с сайта разработчика (lucko) и положите файл в plugins/ для Bukkit-платформ или в mods/ для Fabric и Forge. Перезапуск — и всё.
Проверка:
/sparkЕсли консоль отвечает списком подкоманд, плагин жив. Права: spark для всего, spark.profiler и spark.tps по отдельности, если раздаёте доступ модераторам через LuckPerms.
Важный момент: Spark сам почти не нагружает сервер. Его можно держать постоянно включённым на проде, в отличие от старых профайлеров вроде Timings, которые заметно искажали картину.
Первый взгляд: TPS и MSPT
Прежде чем запускать полноценный сэмплинг, посмотрите общее состояние:
/spark tpsОтвет выглядит примерно так:
TPS from last 5s, 10s, 1m, 5m, 15m:
20.0, 19.98, 18.4, 17.9, 19.1
Tick durations (min/med/95%ile/max ms) from last 10s, 1m:
8.2 / 12.4 / 31.7 / 210.4
CPU usage from last 10s, 1m, 15m:
34%, 41%, 38% (system)Читать надо MSPT, а не TPS. TPS — производная величина, он показывает 20.0 до тех пор, пока средний тик укладывается в 50 мс. Медиана 12 мс при максимуме 210 мс означает, что сервер в целом здоров, но раз в несколько секунд что-то намертво его подвешивает — и вот это «что-то» и надо ловить.
Если медиана уже 40+ мс, у вас не всплески, а системная перегрузка: слишком много сущностей, слишком большой view-distance или мало ядер.
Дополнительно:
/spark health --memory
/spark gcmonitorПервая показывает использование кучи и дисковую нагрузку, вторая начинает писать в чат каждую паузу сборщика мусора. Если GC-паузы идут по 500 мс каждые десять секунд, проблема не в плагинах, а в настройках памяти и флагах JVM.
Запуск профайлера Spark на сервере Minecraft
Основной сценарий:
/spark profiler start --timeout 120Профайлер соберёт данные за две минуты и автоматически выдаст ссылку. Запускайте в момент пиковой нагрузки, когда лаги реально есть — профиль пустого ночного сервера бесполезен.
Полезные ключи:
--only-ticks-over 100— записывать только тики длиннее 100 мс. Идеально для ловли редких фризов: в отчёт не попадёт обычная работа, останутся одни всплески.--thread *— профилировать все потоки, а не только главный. Нужно, когда подозреваете асинхронный плагин или чанк-генерацию.--alloc— профилировать не время, а выделение памяти. Так находят плагины, которые создают мусор мегабайтами и провоцируют GC.--interval 2— интервал сэмплирования в миллисекундах, по умолчанию 4. Мельче даёт точнее, но тяжелее.
Остановить раньше срока:
/spark profiler stopКак читать отчёт
Открывается ссылка вида spark.lucko.me/xxxxxxx, и там дерево вызовов, отсортированное по доле времени. Первое, что нужно сделать — переключиться в режим Merge modes → Separate parent calls и включить Only ticks over, если использовали соответствующий флаг.
Дальше идёте сверху вниз и раскрываете самые толстые ветки. Что обычно находится:
ServerLevel.tickNonPassenger с большим процентом — мобы и сущности. Дальше внутри будет видно, кто именно: Mob.aiStep (поиск пути), Villager.tick (жители, самые дорогие мобы в игре), Item.tick (валяющийся дроп). Лечится лимитами спавна и entity-activation-range.
ChunkMap.tick и ChunkGenerator — генерация чанков. Значит, игроки исследуют новые территории. Помогает прегенерация мира через Chunky и снижение view-distance.
LevelChunk.tickBlockEntity — тайл-энтити: сундуки, воронки, печи. Классический источник лагов на серверах с большими автоматическими фермами. Смотрите HopperBlockEntity — если он в топе, крутите ticks-per.hopper-transfer в spigot.yml.
Имя пакета плагина прямо в дереве — например ru.example.myplugin.Listener.onMove. Это самый приятный вариант: виновник назван по имени. Смотрите, на каком событии он висит. PlayerMoveEvent с тяжёлой логикой внутри — почти всегда криво написанный плагин, потому что событие вызывается десятки раз в секунду на каждого игрока.
SQL, JDBC, HikariCP в главном потоке — плагин лезет в базу синхронно. Каждый запрос блокирует весь сервер. Ищите в конфиге плагина опцию асинхронного режима либо меняйте плагин.
Что делать с находкой
Порядок действий после того, как виновник найден:
- Проверить версию плагина. Половина проблем чинится обновлением — авторы регулярно оптимизируют горячие пути.
- Заглянуть в конфиг: у большинства тяжёлых плагинов есть интервалы проверок, радиусы и кэши, которые по умолчанию выставлены агрессивно.
- Отключить плагин на час и снять профиль заново. Если MSPT упал — подтверждено, если нет — вы поймали следствие, а не причину.
- Только потом лезть в ванильные конфиги.
Про сущности стоит помнить одну вещь: даже идеально настроенный сервер не вытянет ферму железа на десять тысяч жителей. Иногда правильный ответ — не оптимизация, а правило на сервере.
Частые вопросы
Почему Spark показывает 20 TPS, а игроки жалуются на лаги?
Значит, лагает не сервер, а сеть или клиент. Проверьте /spark ping — он покажет пинг игроков с сервера. Если пинги нормальные, а рывки есть, смотрите в сторону клиентских модов и дальности прорисовки у самих игроков.
Чем Spark лучше Timings?
Timings собирает статистику по событиям и задачам плагинов, то есть видит только то, что проходит через API Bukkit. Spark сэмплирует реальный стек JVM, поэтому видит и ванильный код, и внутренности плагинов. На Paper 1.21 Timings объявлен устаревшим и отключён по умолчанию.
Можно ли профилировать прокси?
Да, Spark ставится на BungeeCord и Velocity так же, как на бэкенд. Правда, на прокси лаги почти всегда сетевые, и полезнее будет /spark health, чем сэмплер. Про настройку самого прокси разговор отдельный.
Итог
Рабочий цикл: /spark tps для оценки, /spark profiler start --timeout 120 --only-ticks-over 100 в пик, разбор дерева сверху вниз, точечное исправление, повторный замер. Не меняйте пять вещей сразу — иначе не поймёте, что именно помогло.
Общие рекомендации по разгону собраны в гайде по оптимизации сервера. Если же профиль упорно показывает упор в CPU, а онлайн растёт — вопрос решается железом, посмотрите тарифы.