Почему Minecraft однопоточный, не переписывается на Rust и как на самом деле работают ядра

Руководство Почему Minecraft однопоточный, не переписывается на Rust и как на самом деле работают ядра

Поддерживаемые версии
  1. 1.7
  2. 1.8
  3. 1.9
  4. 1.10
  5. 1.11
  6. 1.12
  7. 1.13
  8. 1.14
  9. 1.15
  10. 1.16
  11. 1.17
  12. 1.18
  13. 1.19
  14. 1.20
  15. 1.21
  16. 26
Каждый администратор сервера рано или поздно задает себе вопрос: «Почему мой сервер лагает, хотя процессор загружен всего на 15%?» Затем мы идем на форумы, видим обещания «многопоточных ядер» за деньги, задумываемся о том, почему бы не переписать игру на C++ или Rust, и почему Mojang такие ленивые, что не сделали игру многопоточной.

В этой статье я хочу раз и навсегда разобрать, как работает архитектура Minecraft, почему распараллелить игру почти невозможно, и что на самом деле спасет ваш TPS.

Правило геймдева: Эмуляция vs Симуляция​

В создании игр есть золотое правило оптимизации: где можно не считать по-настоящему, там нужно эмулировать (создавать видимость), а не симулировать. Например, в большинстве RPG жизнь NPC в соседнем городе не просчитывается детально — игра просто делает вид, что они там есть.

Но в Minecraft это правило применить нельзя. Мир игры строгий. Если игрок построил механизм из редстоуна, загрузил чанк и ушел на другой конец базы, механизм обязан работать с точностью до тика. В игре важна жесткая последовательность событий (симуляция), иначе сломаются фермы, воронки, поршни и вся логика мира.

Миф 1: «Просто разделите игру на разные потоки!»​

Кажется логичным: пусть например один поток считает взрывы, а другой — инвентари. Почему бы и нет?

Представьте ситуацию: игрок открывает сундук и берет оттуда предмет. В эту же миллисекунду крипер взрывает этот сундук.
Если эти процессы идут в разных потоках, возникает так называемая гонка состояний (Race Condition).
  • Вариант А: Игрок инициирует забирание предмета (в сундуке его больше нет), но ещё не успел получить предмет в инвентарь, взрыв взрывает сундук и оттуда ничего не выпадает (там же ничего нет), и в результате предмет исчезает.
  • Вариант Б: Сервер уничтожает сундук, из него выпадает меч, а поток игрока тоже кладет меч ему в инвентарь, в результате происходит дюп.
Чтобы этого не происходило, потоки нужно синхронизировать. Поток инвентаря должен сказать: «Эй, поток взрывов, подожди, пока я не закончу». И в этот момент вся суть многопоточности исчезает, потому что потоки начинают ждать друг друга. Производительность падает, а не растет.

Как оптимизируют на самом деле​

Поскольку основной цикл нельзя просто так распилить, оптимизация строится на двух вещах:
  1. Асинхронность безопасных задач. Из основного потока убирают всё, что не ломает логику мира: работу с сетью, сохранение файлов, просчет освещения, генерацию и загрузку чанков, обработку чата.
  2. Микрооптимизации и отключение мусора. В ванильном ядре полно неоптимального кода. Например, Paper заменяет алгоритм редстоуна на EigenCraft, который работает в разы быстрее. Или еще пример: в ванилле, когда вы открываете сундук, сервер проверяет, а не сидит ли на нем кот? Если сидит — открыть нельзя. Эта механика в мультиплеере не нужна почти никому. Мы убираем эту проверку и получаем буст производительности при работе с воронками и инвентарями.
Всё это есть в Paper и его качественных форках с хорошей репутацией (Purpur, Pufferfish, Leaf и др.).

Важно: Если вы видите в продаже «приватное закрытое ядро, которое делает ваш сервер полностью многопоточным», в 100% случаев — это скам.

Исключение из правил: Folia​

Настоящая многопоточность в Minecraft на данный момент реализована только в проекте Folia от команды PaperMC. Но там используется совершенно другой подход.

Там нет разделения на «поток для мобов» и «поток для инвентарей». Folia делит сам мир на регионы. Если игроки находятся за тысячи блоков друг от друга, их действия никак не могут пересечься, поэтому эти куски мира просчитываются независимыми потоками (Regionised Multithreading).

Это работает, но с оговорками:
  • На границах этих самых регионов всё равно могут возникать неванильные баги.
  • Folia требует переписывания плагинов (обычные плагины под Paper на ней не запустятся).
  • Разгружая процессор, многопоточность требует значительно больше оперативной памяти. Учитывайте это при выборе хостинга.
Кстати, а теперь подумайте вот о чём: архитектура Folia подразумевает, что для эффективной многопоточности игроки должны находиться далеко друг от друга (в разных регионах) и никак не взаимодействовать. Если это так, то точно ли вам нужно именно это ядро?
Возможно, под тематику вашего проекта будет гораздо проще и стабильнее сделать несколько отдельных серверов и связать их через BungeeCord или Velocity. А инвентари, здоровье, голод, эффекты и эндер-сундуки просто синхронизировать между серверами через базу данных. По сути, вы получите ровно то же самое разделение нагрузки, но на проверенных технологиях, без неванильных багов и с поддержкой абсолютно любых плагинов. Подумайте об этом, прежде чем гнаться за Folia.

Миф 2: «Перепишите сервер на C++ или Rust, и он полетит!»​

Звучит круто: системные языки, никакого сборщика мусора, максимальная скорость. Но на практике это утопия, и вот почему:
  1. Масштаб и нелегальность. Чтобы переписать ядро, нужно с нуля воссоздать всю игру, 1 в 1 повторить все ванильные баги и фичи, и успевать за обновлениями Mojang. Кроме того, это незаконно, это нарушает авторские права создателей игры.
  2. Смерть экосистемы плагинов. Java — идеальный язык для моддинга. Можно легко подгружать новые классы «на лету», весь загруженный байткод читаем, плагины могут взаимодействовать друг с другом через Reflection API. В скомпилированных языках вроде C++ или Rust так просто манипулировать логикой других библиотек во время работы сервера невозможно.
  3. На самом деле Java НЕ медленная. Бытует мнение, что Java — медленный язык. Но это лишь иллюзия, которая возникает при оценке скорости старта сервера и высокого потребления оперативной памяти. Однако давайте будем честны: оперативная память сейчас стоит копейки по сравнению с мощными процессорами, на которые реально идет упор. Главное — это скорость в процессе работы.
    Когда сервер запустился, плагины прогрузились и система «прогрелась», в дело вступает JIT-компилятор. Он анализирует код в реальном времени и делает кучу оптимизаций, например если какой-то if почти всегда выдает true, виртуальная машина на уровне машинного кода убирает эту проверку, разгоняя выполнение. В итоге на длинной дистанции скорость Java близка к нативным C++ (а если разработчик на C++ пишет неоптимально, то даже быстрее). А если вы боитесь микро-фризов из-за очистки памяти, то это всё в прошлом, современные сборщики мусора (например ZGC) работают практически мгновенно. Эпоха, когда сервер замирал на секунду из-за очистки памяти, давно прошла.
Единственное исключение, когда переписывание на Rust или C++ имеет смысл — это узкоспециализированные старые серверы. Например, BedWars на Hypixel. Им из игры не нужно ничего кроме только установки блоков, передвижения и PvP, и то старого. Такую сильно урезанную версию игры действительно можно написать на системном языке под конкретные нужды, но для классического выживания это не сработает.

Итог​

Да, нужно смотреть правде в глаза: архитектура игры такова, что даже на самом дорогом и мощном процессоре в мире вытянуть больше 250–300 игроков, находящихся рядом друг с другом (в одном месте/городе), вряд ли получится. Эту задачу просто невозможно распараллелить без поломки логики игры. Но давайте честно — для 99% серверов это не является реальной проблемой.

В остальном же, не ищите волшебную таблетку в виде платных закрытых «супер-ядер» и не ждите чудес от многопоточности. Правильно настроенный Purpur/Leaf, предгенерация мира через Chunky, профилирование бутылочных горлышек через Spark, современная версия Java с самыми передовыми внутренними оптимизациями и отсутствие кривых плагинов — это всё, что вам нужно для стабильных 20 TPS.

А что вы думаете по этому поводу? Сталкивались ли вы с продажей закрытых «многопоточных» ядер и обещаниями 20 TPS при 1000 онлайна? Какое ядро сейчас используете на своих проектах и как боретесь с лагами? Пишите в комментарии, будет интересно обсудить и, возможно, дополнить статью вашим опытом!
Автор
Apeki
Просмотры
14
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок

Другие ресурсы пользователя Apeki

Поделиться ресурсом

Назад
Сверху Снизу