Архитектура Minecraft сети: от одного сервера до кластера

Архитектура Minecraft сети: от одного сервера до кластера

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

Эта статья про то, как правильно масштабировать Minecraft проект. От одиночного Paper-сервера до полноценного кластера с прокси, балансировкой нагрузки и отказоустойчивостью. Без воды, с конфигами и схемами.

Этап 1: один сервер

Самая простая архитектура. Один VPS или выделенный сервер. На нём крутится Paper (или Purpur), все плагины, все миры, все игроки в одном процессе.

Игроки → [Paper Server :25565]
              ├── world/
              ├── world_nether/
              ├── world_the_end/
              └── plugins/

Это работает до определённого порога. Примерно до 80-120 игроков онлайн, в зависимости от железа и типа сервера. Выживание с фермами упрётся в лимит раньше, чем лобби с NPC.

Типичная конфигурация для одиночного сервера:

# server.properties
server-port=25565
online-mode=true
max-players=100
view-distance=10
simulation-distance=8
# Запуск с оптимальными флагами JVM (Aikar's flags)
java -Xms8G -Xmx8G -XX:+UseG1GC -XX:+ParallelRefProcEnabled \
  -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions \
  -XX:+DisableExplicitGC -XX:+AlwaysPreTouch \
  -jar paper-1.21.4.jar nogui

Плюсы:

  • Простота настройки и обслуживания
  • Один конфиг, один процесс
  • Нет проблем с синхронизацией данных
  • Все плагины работают из коробки без дополнительной настройки
  • Минимальные требования к знаниям администратора

Минусы:

  • Minecraft однопоточный по своей сути. Больше ядер не помогут
  • Все игроки на одном инстансе. Лаг на мини-играх = лаг на выживании
  • Нет изоляции. Краш одного плагина убивает весь сервер
  • Невозможно обновить один режим без остановки всего
  • Один большой мир съедает всю оперативную память
  • Бэкапы требуют остановки или рискуешь получить повреждённые данные

Здесь стоит понимать ключевое ограничение Minecraft. Основной игровой цикл (tick loop) работает в одном потоке. Каждые 50 миллисекунд (20 TPS) сервер обрабатывает всю логику: мобов, редстоун, чанки, игроков. Если один тяжёлый процесс (например, загрузка чанков для новых игроков) занимает больше 50 мс, весь сервер лагает.

Это значит, что вертикальное масштабирование (покупка более мощного процессора) имеет потолок. После определённой точки нужно переходить на горизонтальное масштабирование. И тут на сцену выходит прокси.

Когда один сервер перестаёт справляться, не нужно покупать машину помощнее. Нужно менять архитектуру.

Этап 2: когда пора ставить прокси

Чёткие признаки, что пора переходить на сеть:

  • TPS падает ниже 18 при 60+ игроках
  • У тебя больше двух игровых режимов (выживание, мини-игры, креатив)
  • Нужна возможность обновлять один режим, не трогая другие
  • Хочешь распределить нагрузку между несколькими машинами
  • Нужны общие данные между серверами (экономика, ранги, друзья)

Прокси решает главную задачу: игрок подключается к одному адресу, а прокси маршрутизирует его на нужный бэкенд-сервер. Игрок может переключаться между серверами без переподключения.

Есть и менее очевидный плюс. С прокси ты можешь проводить технические работы на одном сервере, пока игроки спокойно играют на других. Нужно обновить плагин на выживании? Перекинь игроков на лобби, обнови, верни обратно. Никого не нужно отключать. Это критично для серверов с 24/7 аптаймом.

Этап 3: базовая сеть с Velocity

Velocity - это современный прокси для Minecraft. Если ты ещё на BungeeCord, переходи. Velocity быстрее, безопаснее (modern forwarding с HMAC-SHA256), и активно развивается. Мы подробно разбирали это в статье о Velocity vs BungeeCord.

Базовая схема:

Игроки → [Velocity Proxy :25565]
               ├── [Lobby :30001]       (Paper)
               ├── [Survival :30002]    (Paper)
               └── [Minigames :30003]   (Paper)

Настройка Velocity

# velocity.toml
bind = "0.0.0.0:25565"
motd = "<green>MyServer Network"
show-max-players = 500
player-info-forwarding-mode = "modern"
online-mode = true

[servers]
lobby = "127.0.0.1:30001"
survival = "127.0.0.1:30002"
minigames = "127.0.0.1:30003"
try = ["lobby"]

[forced-hosts]
"survival.myserver.com" = ["survival"]
"games.myserver.com" = ["minigames"]

Настройка бэкенд-серверов

На каждом Paper-сервере в config/paper-global.yml:

proxies:
  velocity:
    enabled: true
    online-mode: false
    secret: "ваш-секретный-ключ-из-forwarding.secret"

В server.properties каждого бэкенда:

server-port=30001  # уникальный для каждого сервера
online-mode=false  # авторизация через прокси

Ключевой момент: online-mode=false на бэкендах, online-mode=true на Velocity. Прокси проверяет лицензию, бэкенды доверяют прокси через modern forwarding.

Топология сети: Proxy → Lobby → Game Servers

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

  1. Буфер нагрузки. Лобби легковесный, он не грузит процессор
  2. Выбор сервера. Игрок через GUI или команды выбирает куда идти
  3. Fallback. Если игровой сервер падает, игрока кидает обратно на лобби, а не отключает
  4. Обслуживание. Можно перезапустить игровой сервер, не выкидывая игроков из сети
Игрок подключается → Velocity
    → Lobby (первое подключение)
        → /server survival (команда игрока)
            → Survival
        → /server minigames
            → Minigames
    → Если сервер упал → возврат на Lobby

Настройка fallback в Velocity:

[servers]
lobby = "127.0.0.1:30001"
survival = "127.0.0.1:30002"
try = ["lobby"]

[forced-hosts]
"play.myserver.com" = ["lobby"]

Общие базы данных: MySQL и Redis

Когда у тебя несколько серверов, данные нужно синхронизировать. Два основных инструмента: MySQL для постоянного хранения и Redis для кеширования и обмена сообщениями.

MySQL: общие данные

Экономика, ранги, статистика, друзья - всё в одной базе, доступной всем серверам.

# Пример конфига LuckPerms (permissions)
storage-method: MySQL
data:
  address: 127.0.0.1:3306
  database: minecraft_network
  username: minecraft
  password: "strong-password-here"
  pool-settings:
    maximum-pool-size: 10

Каждый плагин, который работает на нескольких серверах, должен использовать MySQL вместо файлового хранилища. LuckPerms, EssentialsX (через экстерналку), плагины экономики.

Redis: кеш и обмен сообщениями

Redis быстрее MySQL для операций, которые происходят часто. Количество игроков онлайн, кеш данных, real-time синхронизация.

# Пример конфига RedisBungee (или аналога для Velocity)
redis:
  host: 127.0.0.1
  port: 6379
  password: "redis-password"

Типичная схема использования:

MySQL: аккаунты, балансы, инвентари, статистика
Redis: онлайн-статус, кеш, межсерверные сообщения, очереди

Обмен сообщениями между серверами

Серверам нужно общаться друг с другом. Игрок на Survival отправляет сообщение другу на Minigames. Глобальный чат. Переводы денег. Приглашения в пати.

Plugin Messaging Channel

Velocity поддерживает BungeeCord plugin messaging channel. Бэкенд-серверы могут отправлять сообщения через прокси:

// Отправка сообщения через plugin messaging
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF("survival");
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());

Redis Pub/Sub

Для более сложной логики лучше использовать Redis Pub/Sub. Каждый сервер подписывается на каналы и может отправлять/получать сообщения:

Survival публикует → Redis канал "global_chat" → Все серверы получают
Minigames публикует → Redis канал "party_invite" → Целевой сервер получает

Это работает даже если серверы на разных машинах.

Пример подписки на Redis Pub/Sub в плагине:

// Подписка на канал
jedis.subscribe(new JedisPubSub() {
    @Override
    public void onMessage(String channel, String message) {
        // Обработка сообщения
        if (channel.equals("global_chat")) {
            Bukkit.broadcastMessage(message);
        }
    }
}, "global_chat", "party_invite", "teleport_request");
// Публикация сообщения
jedis.publish("global_chat", playerName + ": " + chatMessage);

Для большинства задач хватает Redis Pub/Sub. Plugin Messaging Channel ограничен: он работает только когда на обоих серверах есть хотя бы один игрок. Redis работает всегда.

Балансировка нагрузки

Когда у тебя несколько серверов одного типа (например, три сервера мини-игр), нужно распределять игроков между ними.

Round-Robin

Самый простой вариант. Игроки идут по очереди: первый на Minigames-1, второй на Minigames-2, третий на Minigames-3, четвёртый снова на Minigames-1.

# velocity.toml
[servers]
minigames-1 = "10.0.0.11:30003"
minigames-2 = "10.0.0.12:30003"
minigames-3 = "10.0.0.13:30003"

Least Connections

Более умный подход. Игрок идёт на сервер с наименьшим количеством игроков. Реализуется через плагин на Velocity, который проверяет онлайн каждого бэкенда.

Queue-based

Для режимов типа BedWars или SkyWars: игрок встаёт в очередь, система находит свободный сервер (или поднимает новый) и отправляет туда группу игроков.

Безопасность на каждом уровне

Безопасность в многосерверной архитектуре сложнее, чем на одном сервере. Каждый слой требует своей защиты.

Уровень 1: DDoS-защита

Первый слой - фильтрация трафика ДО того, как он попадёт к тебе. Прокси или специализированный DDoS-фильтр перед всей сетью. Подробнее о выборе защиты - в нашей статье о выборе хостинга с DDoS-защитой.

Интернет → [DDoS Filter] → [Velocity :25565] → Backend servers

Уровень 2: файрвол

Бэкенд-серверы не должны быть доступны из интернета напрямую. Только прокси может к ним подключаться:

# На каждом бэкенд-сервере
iptables -A INPUT -p tcp --dport 30001:30010 -s IP_ПРОКСИ -j ACCEPT
iptables -A INPUT -p tcp --dport 30001:30010 -j DROP

Если бэкенд-серверы на той же машине, что и прокси, привязывай их только к localhost. Тогда даже без правил iptables они не будут доступны извне. Но iptables - дополнительный слой защиты, и он не лишний.

Уровень 3: Modern Forwarding

Velocity Modern Forwarding с HMAC-SHA256. Никакого BungeeCord legacy forwarding. Секрет из forwarding.secret должен быть одинаковым на прокси и всех бэкендах, но при этом достаточно сложным. Сгенерируй случайную строку в 32+ символа. Подробнее в чеклисте безопасности.

Уровень 4: база данных

MySQL и Redis слушают только на localhost или внутренней сети. Никакого доступа извне:

# MySQL только на localhost
bind-address = 127.0.0.1

# Redis только на localhost
bind 127.0.0.1
requirepass "сильный-пароль"

Разделение сервисов

На маленькой сети всё может жить на одной машине. Но когда растёшь, нужно разделять.

Одна машина (до 100 игроков)

[Машина 1]
├── Velocity
├── Lobby
├── Survival
├── Minigames
├── MySQL
└── Redis

Две машины (100-300 игроков)

[Машина 1 - Прокси + Лёгкие]        [Машина 2 - Тяжёлые + БД]
├── Velocity                          ├── Survival
├── Lobby                             ├── Minigames
├── Redis                             └── MySQL

Три+ машины (300+ игроков)

[Машина 1 - Proxy]     [Машина 2 - Games]     [Машина 3 - DB]
├── Velocity            ├── Survival            ├── MySQL
├── Lobby               ├── Minigames-1         └── Redis
                        └── Minigames-2

Правило: тяжёлые игровые серверы отдельно от базы данных. БД под нагрузкой может забрать весь I/O диска, и игровые серверы начнут лагать.

Docker для управления серверами

Docker упрощает управление несколькими серверами. Каждый сервер в своём контейнере, изолированная среда, простое масштабирование.

# docker-compose.yml
version: '3.8'

services:
  velocity:
    image: itzg/bungeecord
    environment:
      TYPE: VELOCITY
      VELOCITY_VERSION: "3.4.0"
    ports:
      - "25565:25565"
    volumes:
      - ./velocity:/server
    networks:
      - minecraft

  lobby:
    image: itzg/minecraft-server
    environment:
      TYPE: PAPER
      VERSION: "1.21.4"
      EULA: "TRUE"
      SERVER_PORT: 30001
    volumes:
      - ./lobby:/data
    networks:
      - minecraft

  survival:
    image: itzg/minecraft-server
    environment:
      TYPE: PAPER
      VERSION: "1.21.4"
      EULA: "TRUE"
      SERVER_PORT: 30002
    volumes:
      - ./survival:/data
    networks:
      - minecraft

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root-password
      MYSQL_DATABASE: minecraft
      MYSQL_USER: minecraft
      MYSQL_PASSWORD: mc-password
    volumes:
      - mysql_data:/var/lib/mysql
    networks:
      - minecraft

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass redis-password
    networks:
      - minecraft

networks:
  minecraft:
    driver: bridge

volumes:
  mysql_data:

Docker даёт:

  • Изоляцию между серверами
  • Быстрый деплой новых инстансов
  • Контроль ресурсов (лимиты CPU/RAM на контейнер)
  • Простой откат через образы

Минус: небольшой overhead на виртуализацию. На слабом железе лучше запускать серверы напрямую.

Горизонтальное масштабирование

Горизонтальное масштабирование - добавление новых серверов вместо усиления существующих.

Принцип простой: когда Minigames-1 загружен, ты не покупаешь ему больше RAM, а поднимаешь Minigames-2 на другой машине.

Velocity → [Minigames-1: 45/50 игроков] (загружен)
         → [Minigames-2: 12/50 игроков] (свободен)
         → [Minigames-3: 0/50 игроков]  (только поднят)

Для этого нужно:

  1. Stateless бэкенды. Данные игроков в MySQL/Redis, а не в локальных файлах
  2. Единая конфигурация. Ansible или аналог для раскатки одинаковых настроек
  3. Динамическая регистрация. Плагин на Velocity, который автоматически добавляет новые бэкенды
  4. Мониторинг. Нужно знать загрузку каждого бэкенда для распределения

Высокая доступность

Единая точка отказа - враг номер один. Если Velocity упал, вся сеть недоступна. Если MySQL упал, ничего не работает.

Дублирование прокси

Два Velocity-инстанса за DNS Round-Robin или TCP load balancer:

DNS: play.myserver.com
    → 10.0.0.1 (Velocity-1)
    → 10.0.0.2 (Velocity-2)

Или с помощью HAProxy:

frontend minecraft
    bind *:25565
    default_backend velocity_servers

backend velocity_servers
    balance roundrobin
    server velocity1 10.0.0.1:25565 check
    server velocity2 10.0.0.2:25565 check

MySQL Replication

Master-slave репликация для базы данных. Master принимает записи, slave обслуживает чтение:

Запись → [MySQL Master]
              ↓ (репликация)
Чтение → [MySQL Slave]

Redis Sentinel

Автоматическое переключение при падении Redis:

[Redis Master] ←→ [Redis Slave]
       ↑
[Redis Sentinel] (мониторинг и failover)

Где DDoS-защита в архитектуре

DDoS-защита стоит перед всем. Это самый первый слой, через который проходит весь трафик от игроков.

Интернет
    ↓
[DDoS Filter: MineGuard]   ← фильтрация L3/L4/L7
    ↓
[Velocity Proxy :25565]     ← маршрутизация
    ↓
[Backend Servers]           ← игровая логика
    ↓
[MySQL / Redis]             ← данные

Реальный IP сервера скрыт за DDoS-фильтром. Игроки подключаются к адресу фильтра, фильтр пропускает легитимный трафик и отсекает атаки. Бэкенд-серверы вообще не видят атакующий трафик.

Важно: DDoS-фильтр должен стоять перед прокси, а не после. Если атака дойдёт до Velocity, даже мощный прокси упадёт под объёмной атакой.

Реальные примеры архитектур

Маленькая сеть (50-100 игроков)

Один VPS с 16 GB RAM и 4 ядрами.

[DDoS Filter]
    ↓
[VPS: 16GB RAM]
├── Velocity          (256 MB)
├── Lobby             (512 MB)
├── Survival          (6 GB)
├── Creative          (2 GB)
├── MySQL             (1 GB)
└── Redis             (256 MB)

Бюджет: 30-50 EUR/месяц. Работает стабильно при грамотной оптимизации плагинов. Главное на этом этапе - правильные JVM-флаги и оптимизация конфигов Paper (view-distance, simulation-distance, entity-activation-range).

На что обратить внимание: Velocity на маленькой сети не требует много ресурсов. 256-512 MB RAM хватит для сотен подключений. Но не экономь на RAM для игровых серверов. Лучше дать Survival 8 GB и иметь запас, чем 4 GB с постоянными GC-паузами.

Средняя сеть (200-500 игроков)

Два выделенных сервера. На этом этапе критично разделить тяжёлые процессы.

[DDoS Filter: MineGuard]
    ↓
[Сервер 1: 32GB, 8 ядер]        [Сервер 2: 64GB, 8 ядер]
├── Velocity                      ├── Survival        (12 GB)
├── Lobby           (1 GB)        ├── SkyBlock         (8 GB)
├── Redis                         ├── Minigames-1      (4 GB)
├── MySQL                         └── Minigames-2      (4 GB)

Бюджет: 100-200 EUR/месяц. Выживание и SkyBlock на отдельной машине, потому что они едят больше всего ресурсов. MySQL и Redis остаются на первой машине, потому что прокси и лобби их нагружают минимально.

На этом этапе обязательно настрой мониторинг. Prometheus + Grafana, или хотя бы простой скрипт, который отслеживает TPS, CPU и RAM каждого сервера. Без мониторинга ты не узнаешь о проблеме, пока игроки не начнут жаловаться.

Также на среднем уровне стоит автоматизировать бэкапы. Каждый сервер бэкапится отдельно, бэкапы хранятся на внешнем хранилище (S3, отдельный диск). Потеря данных на одном сервере не должна затрагивать остальные.

Крупная сеть (1000+ игроков)

Кластер из 5+ серверов. Здесь уже полноценный production-grade инфраструктурный проект.

[DDoS Filter]
    ↓
[HAProxy / DNS Round-Robin]
    ↓
[Proxy-1] [Proxy-2]   ← два Velocity за балансировщиком
    ↓
[Lobby-1] [Lobby-2]   ← два лобби для отказоустойчивости
    ↓
[Survival-1] [Survival-2] [Survival-3]  ← кластер выживания
[SkyBlock-1] [SkyBlock-2]               ← кластер SkyBlock
[BedWars-1..10]                          ← пул мини-игр
    ↓
[MySQL Master] → [MySQL Slave-1] [MySQL Slave-2]
[Redis Master] → [Redis Slave] + [Sentinel]

Бюджет: 500+ EUR/месяц. Полная отказоустойчивость, горизонтальное масштабирование, автоматический failover. На этом уровне уже нужен DevOps-инженер или хотя бы администратор с опытом работы с кластерами. Ansible для деплоя, Terraform для инфраструктуры, CI/CD для автоматических обновлений.

Критически важно на крупных сетях: каждый компонент должен быть заменяемым. Упал один из Lobby? Второй подхватывает. Упал MySQL Master? Slave промоутится. Один прокси недоступен? Второй обслуживает трафик. Ни одна точка отказа не должна уронить всю сеть.

Чеклист перед запуском сети

Перед тем как переводить проект на многосерверную архитектуру:

  1. Убедись, что все плагины поддерживают MySQL/сетевое хранилище
  2. Настрой Velocity с modern forwarding
  3. Закрой файрволом порты бэкендов
  4. Проверь, что Redis и MySQL слушают только на внутреннем интерфейсе
  5. Настрой бэкапы для каждого сервера отдельно
  6. Поставь мониторинг (TPS, CPU, RAM на каждый бэкенд)
  7. Подключи DDoS-защиту перед всей сетью
  8. Протестируй failback: что происходит при падении бэкенда
  9. Проверь межсерверную синхронизацию (ранги, баланс, инвентарь)
  10. Напиши документацию по своей архитектуре

Начинай с простого. Один Velocity, лобби и один игровой сервер. Когда это заработает стабильно, добавляй следующие серверы. Не пытайся построить кластер на 10 машин с первого дня.

Архитектура сети - это не финальное состояние, а постоянная эволюция. Растёт проект - растёт инфраструктура. Главное, чтобы фундамент был правильным с самого начала.


Protégez votre serveur contre les attaques DDoS

Protection gratuite avec configuration en 5 minutes. 1 To de bande passante inclus.

Essayer gratuitement


Articles connexes