Serveur minecraft

Dev Blog # 5: Stocker votre île SkyBlock | Hypixel – Monter un serveur MineCraft

Par Titanfall , le 14 janvier 2020 - 11 minutes de lecture

[​IMG]

La

Hey!

Avez-vous déjà lu l'un de nos blogs de développement? Voici un sur notre utilisation de Grafana, un outil pour générer un tas de graphiques sur Hypixel. Dans ces articles de développement, nous parlons du fonctionnement de la technologie sur le réseau.

Aujourd'hui, nous expliquerons comment nous gérons le stockage des îles des joueurs sur Hypixel SkyBlock.
En bref pour les quelques-uns d'entre vous qui n'ont peut-être pas joué: chaque joueur possède son propre monde Minecraft sur le jeu dans lequel il peut construire sa base, générer des ressources à l'aide de sbires et stocker ses objets de valeur dans des coffres. Selon leur rang, les joueurs peuvent créer un certain nombre de profils, chacun avec sa propre île.

La tâche de stockage des mondes Minecraft est facilement divisée en deux: 1. transformer des blocs en fichiers 2. contenir beaucoup de fichiers.

Mais d'abord …
▶ Statistiques SkyBlock (jusque là)

  • Jeu sorti le 11 juin 2019
  • 1,73 million d'îles de joueurs
  • 40,2 Go de données sur les disques
  • Record de 27 000 joueurs simultanés
  • 75 gros ordinateurs exécutant 1500 serveurs Minecraft avec 10 mondes chacun, juste pour les îles des joueurs
  • 3300 sauvegardes et 904 charge d'îlot par minute à 20 000 ccu
  • A commencé le développement en janvier avec 3-4 développeurs à temps plein, avec un prototype construit pour la première fois dans un jeu en interne en novembre

Cliquez sur en savoir plus pour savoir comment le gâteau est cuit.

▶ Transformer des mondes en fichiers

Dossiers du monde Minecraft
Le premier défi consistait à changer les blocs sur lesquels vous cultivez le blé et les porcs à partir desquels vous faites des épées en un tas de 1 et de 0 stockés sur des SSD.

Cela peut sembler très simple si vous avez déjà utilisé un serveur Minecraft, étant donné que le jeu le fait déjà.
Voici à quoi cela ressemble dans l'Explorateur Windows:

[​IMG]La

En fait, nous avons exploité cela en 2015 pour Hypixel Housing, un autre jeu où les joueurs possèdent des mondes (moins d'artisanat, plus de parkour). Qu'est-ce que Housing a fait (dans le code): Sélectionnez tous ces fichiers -> Clic droit -> Envoyer vers -> Dossier compressé (zippé), puis stockez le zip dans une base de données SQL.

Ce processus a bien fonctionné jusqu'à ce que (2 ans plus tard) nous rencontrions des problèmes d'évolutivité, où les 2,5 millions de maisons de joueurs ont utilisé 4 To de données, ce qui était en quelque sorte un goulot d'étranglement à la fois pour l'approvisionnement des machines et sur la base de données. Fondamentalement, le monde du logement était trop grand.

Nous savions également que nous voulions laisser les joueurs posséder plusieurs mondes dans SkyBlock (actuellement sous forme de profils), tandis que le logement ne propose qu'un seul monde.

Dans l'ensemble, nous tirons toujours parti de ce que Minecraft a déjà fait pour le stockage mondial, mais nous avons remixé comment il le fait dans notre propre solution personnalisée …

Format de la région Minecraft: pièges
Le format de fichier Région est le nom de la collection de fichiers composant les mondes minecraft. Leur format est très bien documenté sur le Minecraft Wiki (Region, Level, Chunks), avec un peu de savoir sur wiki.vg.

Nous avons beaucoup d'expérience avec ce format chez Hypixel en raison du nombre de cartes de jeu que nous avons créées et gérées et des quelques implémentations de chargement / enregistrement et NBT à travers différents outils internes et Minecraft PE.

Le format Region est livré en standard avec les outils que nous utilisons (serveur Minecraft, MCEdit, outils de rendu …) et nous continuerons à l'utiliser pour tous nos autres mini-jeux comme Bed Wars et SkyWars. En fait, les îles SkyBlock publiques (The Hub, Gold Island, Nether Fortress, etc …) sont stockées sous forme de fichiers de région réguliers.

Nous avons identifié 4 pièges avec le format Région pour notre cas d'utilisation. La principale différence que nous avons de vanilla Minecraft est que les mondes des mini-jeux ne sont pas infinis. Les fichiers de région sont optimisés pour les joueurs qui traversent des mondes infinis (également appelés streaming mondial), tandis que les mondes SkyWars ou SkyBlock se déroulent généralement en blocs de 16 x 16, qui peuvent tous être chargés en une seule fois et conservés en mémoire (et manger toute votre RAM à partir de 1,8. 9 fuites).

Voici les 4 pièges (cela pourrait devenir technique):

1. Les fichiers de région accumulent des données inutiles supplémentaires au fil du temps
Les fichiers sont divisés en secteurs de 4 Ko. Chaque morceau prend prend au moins (et généralement) 1 secteur. Étant donné que la taille du bloc (en octets) est pré-suspendue avec sa longueur, Minecraft ne prend pas la peine d'effacer chaque secteur avant d'écrire dessus.

Cela signifie que plus vous jouez (ou construisez) sur un monde Minecraft, plus ses fichiers mondiaux s'accumulent et plus ils grossissent. Cela n'a généralement pas d'importance lorsque vous jouez à la survie, mais cela importe lorsque vous stockez beaucoup, beaucoup de mondes.

2. Les fichiers de région se compressent par morceau et ont beaucoup de remplissage
Pour simplifier les E / S mondiales, chaque bloc est compressé individuellement, avec son propre en-tête zlib. Regrouper le tout offre un meilleur taux de compression. Le rembourrage est généralement annulé lors de la fermeture éclair du monde entier, mais peut encore laisser couler quelques (alias milliers) octets de données supplémentaires ici et là.

3. Chunk Format contient beaucoup de données dont nous n'avons pas besoin
Il y a deux parties à cela.
Tout d'abord, le contenu NBT a des champs inutiles (pour nous), comme "LastUpdate", "InhabitedTime", "LightPopulated", "TerrainPopulated", xPos, Zpos ….
Deuxièmement, l'utilisation de NBT n'est pas idéale pour la taille car elle contient les noms de champ. Il peut être remplacé par un format binaire versionné simple.

4. Zlib a 24 ans
Zlib / gzip (DEFLATE …) est la bibliothèque de compression utilisée par le serveur vanilla Minecraft pour sauver ses mondes.

Une bibliothèque est essentiellement un tas de code destiné à être réutilisé, tandis que la compression est le processus magique (alias maths) de transformation de gros fichiers en petits fichiers. Zlib est omniprésent, mais il y a eu des progrès dans le domaine de la compression depuis sa sortie. Giant tech (Google, Facebook …) a investi des millions en R&D et open source leur travail (rendu public).

Pour la compression, nos exigences sont les suivantes: besoin d'un taux de compression élevé, car de nombreux fichiers, et la compression doit être plus rapide que la décompression, car nous le faisons plus.

Après avoir examiné quelques options (y compris les essayer sur Minecraft et juger qui d'autre utilise la bibliothèque), nous avons atterri sur Zstd (liaisons Java).

[​IMG]
5 fois plus rapide ET 2,5 fois plus petitLa

Présentation: le format Slime World

C'est un nouveau format de fichier, comme un .doc ou un .html, mais à la place c'est .slime!

Slime corrige les points soulignés ci-dessus, tout en respectant de nombreuses «normes» Minecraft, parfois pour que la compatibilité logicielle soit plus facile, parfois pour les performances.

Définir un format de fichier est peut-être le plus ennuyeux de tous les temps, mais essayons-le (c'est aussi technique):

———-
Format de fichier «Slime»
2 octets – magie = 0xB10B
1 octet (ubyte) – version, actuelle = 0x03
2 octets (court) – xPos du bloc le plus bas x et le plus bas z
2 octets (court) – zPos
2 octets (ushort) – largeur
2 octets (ushort) – profondeur
[depends] – masque bitmap en morceaux
-> chaque bloc est de 1 bit: 0 si tout l'air (manquant), 1 s'il est présent
-> les morceaux sont classés zx, ce qui signifie
-> le dernier octet contient des bits inutilisés à droite
-> la taille est ceil ((largeur * profondeur) / 8) octets

4 octets (int) – taille des morceaux compressés
4 octets (int) – taille des morceaux non compressés
(taille déterminée à partir du masque binaire)
compressé à l'aide de zstd

4 octets (int) – taille des entités de tuile compressées
4 octets (int) – taille des entités de tuile non compressées

même format que mc,
à l'intérieur d'une liste nbt nommée "tuiles", dans un composé global, pas de gzip n'importe où
compressé à l'aide de zstd

1 octet (booléen) – a des entités
[if has entities]
Taille des entités compressées de 4 octets (int)
Taille des entités non compressées de 4 octets (int)

Même format que mc SAUF en option «CustomId»
à côté une liste nbt nommée «entités», dans le composé global
Compressé à l'aide de zstd

4 octets (int) – taille «extra» compressée
4 octets (int) – taille «extra» non compressée
[depends] – balise composée compressée à l'aide de zstd

Format de morceau personnalisé
256 pouces – carte des hauteurs
256 octets – biomes
2 octets – sections bitmask (de bas en haut)
2048 octets – bloquer la lumière
4096 octets – blocs
2048 octets – données
2048 octets – puits de lumière
2 octets (ushort) – taille HypixelBlocks3 (0 si absent)
[depends] – HypixelBlocks3
Pour chaque section
———-
Si vous ne voyez pas d'indentation: https://pastebin.com/raw/EVCNAmkw

Remarque HypixelBlocks3, qui est un cache pour le stockage 1.9+. Les entités CustomIds doivent pouvoir sérialiser des classes d'entités personnalisées.

Il pourrait y avoir des économies supplémentaires en:
1) Commande de blocs dans les colonnes XZY et utilisation de la table des hauteurs pour la hauteur y
2) Stockage des blocs sur 12 bits (id 8 bits + type 4 bits) car nous n'exécutons que 1.8.9
3) Combiner le quartet du puits de lumière dans chacun des 4 bits restants (même bon pour la compression, car le puits de lumière change généralement une fois par colonne y)

MAIS!
Il est préférable pour la vitesse de chargement d'utiliser le même format de bloc que la représentation en mémoire (bouquet de grignotages, palette de blocs de 13 bits, HypixelBlocks3). Il y a de fortes chances que la différence de taille soit compressée.

Historique des versions:
– V1: version initiale
– V2: Ajout de la balise nbt "extra" pour les données personnalisées par monde
– V3: Ajout du stockage des entités

Voici une vidéo expliquant visuellement les pièges du format régional:

Notre intégration du format Slime dans Craftbukkit se fait en utilisant des "mondes en mémoire", qui n'utilisent pas du tout le stockage sur disque. La plupart des éléments de notre logiciel serveur sont publics pour éviter toute réflexion. Nous instancions le monde nms et passons un IDataManager surchargé, dont createChunkLoader (le nom peut varier) renvoie un ChunkRegionLoader surchargé qui contient les blocs nms préchargés en mémoire.

Autre remarque: nous stockons les blocs, les entités et les entités de tuiles dans des tableaux séparés dans l'espoir de meilleurs taux de compression.

Il n'y a pas de plugin publiquement disponible pour l'enregistrement / chargement de slime pour le moment car trop de liens avec du code personnalisé que nous ne pouvons pas partager.

Analyse des économies de scénarios réels

Tous les mumbo-jumbo ci-dessus permettent d'utiliser pour économiser de nombreux Go de données.

Avant de déployer le format Slime à grande échelle, nous avons fait quelques tests sur nos mondes Hypixel existants en utilisant un petit programme appelé slime-tools. Si vous êtes un développeur et savez utiliser la ligne de commande (ou un décompilateur), vous pouvez télécharge le [HERE].
(Notez que nous n'offrons aucun support pour cet outil)

Résultats agrégés pour différents types de jeux:
Ce sont le facteur d'économie moyen de la boue par rapport à la fermeture éclair du monde Minecraft.

Code:

hg: 3.179x (31% du zip)
sw: 5.032x (20% du zip)
smash: 8.34x (12% du zip)
mcgo: 4.209x (24% du zip)
bedwars: 10.246x (10% de zip)
mw: 2.905x (34% du zip)
bb: 59,56x (2% de zip)
logement: 5.358x (19% du zip)

[​IMG]

[​IMG]

Le jeu le plus comparable à SkyBlock en termes de mondes est Bed Wars. La raison en est que le logement a fait des économies en raison des copies d'îles (oui, les îles au loin dans le logement sont stockées sur le disque). Voici à quoi ressemble un monde du logement: https://staticassets.hypixel.net/news/5c442d9fd200f.image (7) .png

Build Battle a un facteur 60x incroyable en raison de copies alignées de morceaux qui semblent être complètement compressées (c'est une théorie seulement). Build Battle a de nombreuses copies de la carte sur le disque. Exemple de construction d'un monde de bataille: https://staticassets.hypixel.net/news/5c442e4e3e4cb.image (8) .png

Un autre point est que la désactivation d'HypixelBlocks3 dans un contexte mono-version entraînerait une réduction de 10% à 35% de la taille du fichier .slime. Il pourrait même être désactivé sur Hypixel mais cela nécessite un processeur sur une charge mondiale que nous ne pouvons pas épargner. (HypixelBlocks3 est un cache de 1,9 + format de blocs stocké dans chaque section de morceau)

▶ Tenir beaucoup de fichiers
Algues FS

Le deuxième défi est de savoir comment stocker et gérer tous les mondes des joueurs.
Ce problème est compliqué car:

  • Il existe de nombreux serveurs qui auront besoin d'un accès rapide à ces mondes
  • Le jeu ne peut pas descendre
  • Les joueurs se soucient des mondes, cela doit fonctionner même si un ordinateur explose
  • Tout ce qui détient ces mondes doit être simple et documenté

Nous avons examiné quelques options différentes pour stocker tous les fichiers .slime et avons décidé d'utiliser SeaweedFS (https://github.com/chrislusf/seaweedfs). Il s'agit essentiellement d'Amazon S3, mais auto-hébergé.

Nous avons dû développer notre propre script de sauvegarde et de surveillance, en interface avec SeaweedFS.
Les sauvegardes de l'ensemble de données sont effectuées deux fois par jour et stockées dans S3 pendant quelques semaines.

Nous exécutons SeaweedFS sur 3 serveurs de volumes qui utilisent tous des ressources très faibles, répliquant toujours les volumes sur les 3 serveurs pour la disponibilité et la tranquillité d'esprit.

Le FID Seaweed est stocké dans Mongo (comme le reste de nos données de joueur).

Les mondes sont stockés lorsque le jeu est fermé sur un serveur, ce qui se produit quelques dizaines de secondes seulement après que le monde du jeu a eu 0 joueurs. Ils sont également stockés toutes les quelques minutes, plus souvent si les joueurs ont beaucoup interagi avec le monde. C'est pourquoi il y a beaucoup plus d'économies que de chargement.

La taille de chargement moyenne (c'est-à-dire la taille .slime) est enregistrée lorsqu'un monde est réellement chargé. Ce chiffre est environ 80% plus élevé que la taille moyenne sur disque par monde, probablement parce que les mondes actifs ont plus de choses en cours que les inactifs.

[​IMG]

Ce graphique surveille le temps qu'il faut par tâche pour charger votre monde. Notez que la seule chose sur le thread principal (instancier le jeu Skyblock) prend moins d'une tique à cause des mondes en mémoire et d'autres modifications, nous permettant d'ajouter / supprimer librement des mondes à la volée.


J'espère que cela vous donne un bon aperçu de la façon dont nous stockons toutes les îles SkyBlock! Il y a beaucoup plus dans la technologie SkyBlock que nous pourrons couvrir à l'avenir, alors gardez l'œil ouvert.

:)

Cliquez pour agrandir…

Click to rate this post!
[Total: 0 Average: 0]

Commentaires

Laisser un commentaire

Votre commentaire sera révisé par les administrateurs si besoin.