Architektura sieci Minecraft: od jednego serwera do klastra
Każdy projekt Minecraft zaczyna się tak samo. Jeden serwer, paru znajomych, waniliowy survival. Potem pojawiają się pluginy, potem minigry, potem przychodzą setki graczy i nagle rozumiesz: jeden serwer już nie daje rady.
Ten artykuł jest o tym, jak dobrze skalować projekt Minecraft. Od pojedynczego serwera Paper do pełnego klastra z proxy, balansowaniem obciążenia i odpornością na awarie. Bez lania wody, z configami i schematami.
Etap 1: jeden serwer
Najprostsza architektura. Jeden VPS albo dedyk. Kręci się na nim Paper (albo Purpur), wszystkie pluginy, wszystkie światy, wszyscy gracze w jednym procesie.
Gracze → [Paper Server :25565]
├── world/
├── world_nether/
├── world_the_end/
└── plugins/
Działa to do pewnego progu. Mniej więcej do 80-120 graczy online, w zależności od sprzętu i typu serwera. Survival z farmami uderzy w limit szybciej niż lobby z NPC.
Typowa konfiguracja dla pojedynczego serwera:
# server.properties
server-port=25565
online-mode=true
max-players=100
view-distance=10
simulation-distance=8
# Start z optymalnymi flagami 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
Plusy:
- Prostota konfiguracji i utrzymania
- Jeden config, jeden proces
- Brak problemów z synchronizacją danych
- Wszystkie pluginy działają od razu bez dodatkowej konfiguracji
- Minimalne wymagania wiedzy od admina
Minusy:
- Minecraft jest z natury jednowątkowy. Więcej rdzeni nie pomoże
- Wszyscy gracze na jednej instancji. Lag na minigrach = lag na survivalu
- Brak izolacji. Crash jednego pluginu zabija cały serwer
- Nie da się zaktualizować jednego trybu bez zatrzymania całości
- Jeden duży świat zżera cały RAM
- Backupy wymagają zatrzymania albo ryzykujesz uszkodzone dane
Warto tu zrozumieć kluczowe ograniczenie Minecrafta. Główna pętla gry (tick loop) działa w jednym wątku. Co 50 milisekund (20 TPS) serwer obrabia całą logikę: moby, redstone, chunki, graczy. Jeśli jakiś ciężki proces (na przykład ładowanie chunków dla nowych graczy) zajmuje więcej niż 50 ms, cały serwer laguje.
To oznacza, że skalowanie pionowe (kupno mocniejszego procesora) ma sufit. Po pewnym punkcie trzeba przejść na skalowanie poziome. I tu na scenę wchodzi proxy.
Kiedy jeden serwer przestaje dawać radę, nie trzeba kupować mocniejszej maszyny. Trzeba zmienić architekturę.
Etap 2: kiedy pora postawić proxy
Wyraźne oznaki, że pora przejść na sieć:
- TPS spada poniżej 18 przy 60+ graczach
- Masz więcej niż dwa tryby gry (survival, minigry, creative)
- Potrzebujesz możliwości aktualizacji jednego trybu bez ruszania pozostałych
- Chcesz rozłożyć obciążenie między kilka maszyn
- Potrzebujesz wspólnych danych między serwerami (ekonomia, rangi, znajomi)
Proxy rozwiązuje główne zadanie: gracz łączy się z jednym adresem, a proxy kieruje go na odpowiedni serwer backendowy. Gracz może przełączać się między serwerami bez przelogowywania.
Jest też mniej oczywisty plus. Z proxy możesz robić prace techniczne na jednym serwerze, podczas gdy gracze spokojnie grają na innych. Trzeba zaktualizować plugin na survivalu? Przerzuć graczy na lobby, zaktualizuj, wróć ich z powrotem. Nikogo nie trzeba odłączać. To krytyczne dla serwerów z uptime'em 24/7.
Etap 3: podstawowa sieć z Velocity
Velocity to nowoczesne proxy dla Minecrafta. Jeśli wciąż siedzisz na BungeeCord, przechodź. Velocity jest szybsze, bezpieczniejsze (modern forwarding z HMAC-SHA256) i aktywnie rozwijane. Rozgrzebywaliśmy to dokładnie w artykule o Velocity vs BungeeCord.
Podstawowy schemat:
Gracze → [Velocity Proxy :25565]
├── [Lobby :30001] (Paper)
├── [Survival :30002] (Paper)
└── [Minigames :30003] (Paper)
Konfiguracja 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"]
Konfiguracja serwerów backendowych
Na każdym serwerze Paper w config/paper-global.yml:
proxies:
velocity:
enabled: true
online-mode: false
secret: "twoj-sekretny-klucz-z-forwarding.secret"
W server.properties każdego backendu:
server-port=30001 # unikalny dla każdego serwera
online-mode=false # autoryzacja przez proxy
Kluczowy moment: online-mode=false na backendach, online-mode=true na Velocity. Proxy sprawdza licencję, backendy ufają proxy przez modern forwarding.
Topologia sieci: Proxy -> Lobby -> Game Servers
Prawidłowa topologia zakłada, że każdy nowy gracz trafia najpierw na lobby. Jest to ważne z kilku powodów:
- Bufor obciążenia. Lobby jest lekkie, nie obciąża procesora
- Wybór serwera. Gracz przez GUI albo komendy wybiera, dokąd iść
- Fallback. Jeśli serwer gry padnie, gracz zostaje wyrzucony z powrotem na lobby, a nie rozłączony
- Obsługa. Można zrestartować serwer gry bez wyrzucania graczy z sieci
Gracz się łączy -> Velocity
-> Lobby (pierwsze podłączenie)
-> /server survival (komenda gracza)
-> Survival
-> /server minigames
-> Minigames
-> Jeśli serwer padł -> powrót na Lobby
Konfiguracja fallback w Velocity:
[servers]
lobby = "127.0.0.1:30001"
survival = "127.0.0.1:30002"
try = ["lobby"]
[forced-hosts]
"play.myserver.com" = ["lobby"]
Wspólne bazy danych: MySQL i Redis
Kiedy masz kilka serwerów, dane trzeba synchronizować. Dwa główne narzędzia: MySQL do stałego przechowywania i Redis do cache'u i wymiany wiadomości.
MySQL: wspólne dane
Ekonomia, rangi, statystyki, znajomi - wszystko w jednej bazie, dostępnej dla wszystkich serwerów.
# Przykład configu 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
Każdy plugin, który działa na kilku serwerach, powinien używać MySQL zamiast storage'u plikowego. LuckPerms, EssentialsX (przez zewnętrzny moduł), pluginy ekonomii.
Redis: cache i wymiana wiadomości
Redis jest szybszy od MySQL dla operacji, które zdarzają się często. Liczba graczy online, cache danych, synchronizacja real-time.
# Przykład configu RedisBungee (albo odpowiednika dla Velocity)
redis:
host: 127.0.0.1
port: 6379
password: "redis-password"
Typowy schemat użycia:
MySQL: konta, salda, ekwipunki, statystyki
Redis: status online, cache, wiadomości między serwerami, kolejki
Wymiana wiadomości między serwerami
Serwery muszą się ze sobą komunikować. Gracz na Survivalu wysyła wiadomość koledze na Minigames. Globalny czat. Przelewy pieniędzy. Zaproszenia do party.
Plugin Messaging Channel
Velocity wspiera BungeeCord plugin messaging channel. Serwery backendowe mogą wysyłać wiadomości przez proxy:
// Wysyłanie wiadomości przez plugin messaging
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF("survival");
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
Redis Pub/Sub
Do bardziej złożonej logiki lepiej używać Redis Pub/Sub. Każdy serwer subskrybuje kanały i może wysyłać/odbierać wiadomości:
Survival publikuje -> Redis kanal "global_chat" -> Wszystkie serwery odbieraja
Minigames publikuje -> Redis kanal "party_invite" -> Serwer docelowy odbiera
Działa to nawet jeśli serwery są na różnych maszynach.
Przykład subskrypcji na Redis Pub/Sub w pluginie:
// Subskrypcja kanalu
jedis.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
// Obsluga wiadomosci
if (channel.equals("global_chat")) {
Bukkit.broadcastMessage(message);
}
}
}, "global_chat", "party_invite", "teleport_request");
// Publikacja wiadomosci
jedis.publish("global_chat", playerName + ": " + chatMessage);
Do większości zadań wystarcza Redis Pub/Sub. Plugin Messaging Channel ma ograniczenie: działa tylko gdy na obu serwerach jest przynajmniej jeden gracz. Redis działa zawsze.
Balansowanie obciążenia
Kiedy masz kilka serwerów tego samego typu (na przykład trzy serwery minigier), trzeba rozkładać graczy między nimi.
Round-Robin
Najprostszy wariant. Gracze idą po kolei: pierwszy na Minigames-1, drugi na Minigames-2, trzeci na Minigames-3, czwarty znów na 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
Mądrzejsze podejście. Gracz idzie na serwer z najmniejszą liczbą graczy. Realizowane przez plugin na Velocity, który sprawdza online każdego backendu.
Queue-based
Do trybów typu BedWars albo SkyWars: gracz staje w kolejce, system znajduje wolny serwer (albo podnosi nowy) i wysyła tam grupę graczy.
Bezpieczeństwo na każdym poziomie
Bezpieczeństwo w architekturze wieloserwerowej jest trudniejsze niż na jednym serwerze. Każda warstwa wymaga swojej ochrony.
Poziom 1: ochrona DDoS
Pierwsza warstwa to filtracja ruchu ZANIM dotrze do ciebie. Proxy albo wyspecjalizowany filtr DDoS przed całą siecią. Więcej o wyborze ochrony w naszym artykule o wyborze hostingu z ochroną DDoS.
Internet -> [DDoS Filter] -> [Velocity :25565] -> Backend servers
Poziom 2: firewall
Serwery backendowe nie powinny być dostępne z internetu bezpośrednio. Tylko proxy może się do nich łączyć:
# Na kazdym serwerze backendowym
iptables -A INPUT -p tcp --dport 30001:30010 -s IP_PROXY -j ACCEPT
iptables -A INPUT -p tcp --dport 30001:30010 -j DROP
Jeśli serwery backendowe są na tej samej maszynie co proxy, bindować je tylko na localhost. Wtedy nawet bez reguł iptables nie będą dostępne z zewnątrz. Ale iptables to dodatkowa warstwa ochrony i nie zaszkodzi.
Poziom 3: Modern Forwarding
Velocity Modern Forwarding z HMAC-SHA256. Żadnego BungeeCord legacy forwarding. Sekret z forwarding.secret musi być taki sam na proxy i wszystkich backendach, ale wystarczająco skomplikowany. Wygeneruj losowy string 32+ znaków. Więcej w checkliście bezpieczeństwa.
Poziom 4: baza danych
MySQL i Redis słuchają tylko na localhost albo wewnętrznej sieci. Żadnego dostępu z zewnątrz:
# MySQL tylko na localhost
bind-address = 127.0.0.1
# Redis tylko na localhost
bind 127.0.0.1
requirepass "silne-haslo"
Rozdzielanie serwisów
W małej sieci wszystko może żyć na jednej maszynie. Ale kiedy rośniesz, trzeba rozdzielać.
Jedna maszyna (do 100 graczy)
[Maszyna 1]
├── Velocity
├── Lobby
├── Survival
├── Minigames
├── MySQL
└── Redis
Dwie maszyny (100-300 graczy)
[Maszyna 1 - Proxy + Lekkie] [Maszyna 2 - Ciezkie + DB]
├── Velocity ├── Survival
├── Lobby ├── Minigames
├── Redis └── MySQL
Trzy+ maszyny (300+ graczy)
[Maszyna 1 - Proxy] [Maszyna 2 - Games] [Maszyna 3 - DB]
├── Velocity ├── Survival ├── MySQL
├── Lobby ├── Minigames-1 └── Redis
└── Minigames-2
Reguła: ciężkie serwery gry oddzielnie od bazy danych. Baza pod obciążeniem może zająć cały I/O dysku i serwery gry zaczną lagować.
Docker do zarządzania serwerami
Docker upraszcza zarządzanie kilkoma serwerami. Każdy serwer we własnym kontenerze, izolowane środowisko, proste skalowanie.
# 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 daje:
- Izolację między serwerami
- Szybki deploy nowych instancji
- Kontrolę zasobów (limity CPU/RAM na kontener)
- Łatwy rollback przez obrazy
Minus: niewielki overhead na wirtualizację. Na słabym sprzęcie lepiej uruchamiać serwery bezpośrednio.
Skalowanie poziome
Skalowanie poziome to dodawanie nowych serwerów zamiast wzmacniania istniejących.
Zasada prosta: kiedy Minigames-1 jest obciążony, nie kupujesz mu więcej RAM-u, tylko podnosisz Minigames-2 na innej maszynie.
Velocity -> [Minigames-1: 45/50 graczy] (obciazony)
-> [Minigames-2: 12/50 graczy] (wolny)
-> [Minigames-3: 0/50 graczy] (dopiero podniesiony)
Do tego potrzebujesz:
- Stateless backendy. Dane graczy w MySQL/Redis, a nie w lokalnych plikach
- Jedna konfiguracja. Ansible albo odpowiednik do rolowania takich samych ustawień
- Dynamiczna rejestracja. Plugin na Velocity, który automatycznie dodaje nowe backendy
- Monitoring. Musisz znać obciążenie każdego backendu do rozłożenia ruchu
Wysoka dostępność
Pojedynczy punkt awarii to wróg numer jeden. Jeśli Velocity padnie, cała sieć niedostępna. Jeśli MySQL padnie, nic nie działa.
Dublowanie proxy
Dwie instancje Velocity za DNS Round-Robin albo TCP load balancerem:
DNS: play.myserver.com
-> 10.0.0.1 (Velocity-1)
-> 10.0.0.2 (Velocity-2)
Albo przez 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
Replikacja master-slave dla bazy danych. Master przyjmuje zapisy, slave obsługuje odczyt:
Zapis -> [MySQL Master]
| (replikacja)
Odczyt -> [MySQL Slave]
Redis Sentinel
Automatyczne przełączanie przy awarii Redis:
[Redis Master] <-> [Redis Slave]
^
[Redis Sentinel] (monitoring i failover)
Gdzie w architekturze jest ochrona DDoS
Ochrona DDoS stoi przed wszystkim. To pierwsza warstwa, przez którą przechodzi cały ruch od graczy.
Internet
|
[DDoS Filter: MineGuard] <- filtracja L3/L4/L7
|
[Velocity Proxy :25565] <- routing
|
[Backend Servers] <- logika gry
|
[MySQL / Redis] <- dane
Prawdziwy IP serwera jest schowany za filtrem DDoS. Gracze łączą się z adresem filtra, filtr przepuszcza ruch prawdziwych graczy i odcina ataki. Serwery backendowe w ogóle nie widzą ruchu atakującego.
Ważne: filtr DDoS musi stać przed proxy, nie za nim. Jeśli atak dojdzie do Velocity, nawet mocne proxy padnie pod objętościowym atakiem.
Przykłady realnych architektur
Mała sieć (50-100 graczy)
Jeden VPS z 16 GB RAM i 4 rdzeniami.
[DDoS Filter]
|
[VPS: 16GB RAM]
├── Velocity (256 MB)
├── Lobby (512 MB)
├── Survival (6 GB)
├── Creative (2 GB)
├── MySQL (1 GB)
└── Redis (256 MB)
Budżet: 30-50 EUR/miesiąc. Działa stabilnie przy sensownej optymalizacji pluginów. Najważniejsze na tym etapie to prawidłowe flagi JVM i optymalizacja configów Paper (view-distance, simulation-distance, entity-activation-range).
Na co zwrócić uwagę: Velocity w małej sieci nie wymaga dużych zasobów. 256-512 MB RAM wystarczy na setki połączeń. Ale nie oszczędzaj na RAM-ie dla serwerów gry. Lepiej dać Survivalowi 8 GB i mieć zapas niż 4 GB z ciągłymi pauzami GC.
Średnia sieć (200-500 graczy)
Dwa dedykowane serwery. Na tym etapie krytycznie jest rozdzielić ciężkie procesy.
[DDoS Filter: MineGuard]
|
[Serwer 1: 32GB, 8 rdzeni] [Serwer 2: 64GB, 8 rdzeni]
├── Velocity ├── Survival (12 GB)
├── Lobby (1 GB) ├── SkyBlock (8 GB)
├── Redis ├── Minigames-1 (4 GB)
├── MySQL └── Minigames-2 (4 GB)
Budżet: 100-200 EUR/miesiąc. Survival i SkyBlock na osobnej maszynie, bo zżerają najwięcej zasobów. MySQL i Redis zostają na pierwszej maszynie, bo proxy i lobby obciążają je minimalnie.
Na tym etapie obowiązkowo skonfiguruj monitoring. Prometheus + Grafana, albo chociaż prosty skrypt, który śledzi TPS, CPU i RAM każdego serwera. Bez monitoringu nie dowiesz się o problemie, dopóki gracze nie zaczną się skarżyć.
Na średnim poziomie warto też zautomatyzować backupy. Każdy serwer backupowany osobno, backupy trzymane na zewnętrznym storage (S3, osobny dysk). Utrata danych na jednym serwerze nie powinna dotyczyć pozostałych.
Duża sieć (1000+ graczy)
Klaster z 5+ serwerów. Tu już pełny projekt infrastrukturalny klasy production.
[DDoS Filter]
|
[HAProxy / DNS Round-Robin]
|
[Proxy-1] [Proxy-2] <- dwa Velocity za balanserem
|
[Lobby-1] [Lobby-2] <- dwa lobby dla HA
|
[Survival-1] [Survival-2] [Survival-3] <- klaster survival
[SkyBlock-1] [SkyBlock-2] <- klaster SkyBlock
[BedWars-1..10] <- pula minigier
|
[MySQL Master] -> [MySQL Slave-1] [MySQL Slave-2]
[Redis Master] -> [Redis Slave] + [Sentinel]
Budżet: 500+ EUR/miesiąc. Pełna odporność na awarie, skalowanie poziome, automatyczny failover. Na tym poziomie potrzebujesz już inżyniera DevOps albo przynajmniej admina z doświadczeniem w klastrach. Ansible do deployu, Terraform do infrastruktury, CI/CD do automatycznych aktualizacji.
Krytycznie ważne w dużych sieciach: każdy komponent musi być wymienialny. Padło jedno Lobby? Drugie przejmuje ruch. Padł MySQL Master? Slave promuje się na mastera. Jedno proxy niedostępne? Drugie obsługuje ruch. Żaden pojedynczy punkt awarii nie powinien położyć całej sieci.
Checklista przed uruchomieniem sieci
Zanim przeniesiesz projekt na architekturę wieloserwerową:
- Upewnij się, że wszystkie pluginy wspierają MySQL/sieciowy storage
- Skonfiguruj Velocity z modern forwarding
- Zamknij firewallem porty backendów
- Sprawdź, że Redis i MySQL słuchają tylko na wewnętrznym interfejsie
- Skonfiguruj backupy dla każdego serwera osobno
- Postaw monitoring (TPS, CPU, RAM na każdy backend)
- Podłącz ochronę DDoS przed całą siecią
- Przetestuj failback: co się dzieje przy awarii backendu
- Sprawdź synchronizację między serwerami (rangi, saldo, ekwipunek)
- Napisz dokumentację swojej architektury
Zaczynaj od prostego. Jedno Velocity, lobby i jeden serwer gry. Kiedy to zacznie działać stabilnie, dodawaj kolejne serwery. Nie próbuj zbudować klastra na 10 maszyn od pierwszego dnia.
Architektura sieci to nie finalny stan, tylko ciągła ewolucja. Rośnie projekt - rośnie infrastruktura. Najważniejsze, żeby fundament był prawidłowy od samego początku.
Chroń swój serwer przed atakami DDoS
Darmowa ochrona z konfiguracją w 5 minut. 1 TB ruchu w zestawie.
Wypróbuj za darmoPowiązane artykuły
Ochrona Java Edition vs Bedrock Edition: gdzie tkwi roznica
Omawiamy, dlaczego ochrona serwerow Java i Bedrock wymaga zupelnie roznych podejsc i co wazne dla wlasciciela serwera.
Jak skonfigurować własną domenę dla serwera Minecraft
Szczegółowy przewodnik po podłączeniu własnej domeny do serwera Minecraft: rekordy DNS, rekordy SRV, integracja z ochroną MineGuard i typowe błędy.
DiscordSRV dla SMP: zaawansowana konfiguracja, role sync i automatyzacja eventow
Zaawansowane DiscordSRV: role sync z LuckPerms, /link, osobne kanaly na smierci i osiagniecia, kanal konsoli, voice i tuning pod 200+ graczy.