Bonnes pratiques pour utiliser Cloud Spanner en tant que base de données de gaming

Ce document décrit les bonnes pratiques pour utiliser Spanner en tant que base de données backend principale pour stocker l'état d'un jeu. Vous pouvez employer Spanner plutôt que les bases de données courantes pour stocker les données d'authentification des joueurs et les données d'inventaire. Ce document est destiné aux ingénieurs de backend de jeu qui veulent stocker l'état d'un jeu à long terme, ainsi qu'aux opérateurs et administrateurs d'infrastructure de jeu qui souhaitent héberger leur base de données backend sur Google Cloud.

Les jeux multijoueurs et en ligne ont évolué et nécessitent aujourd'hui des structures de base de données de plus en plus complexes pour suivre les droits, l'état et les données d'inventaire des joueurs. Les bases de joueurs grandissantes et la complexité croissante des jeux ont conduit à des solutions de base de données difficiles à adapter et à gérer, qui requièrent souvent une segmentation ou un clustering. Le suivi des éléments dans le jeu (in-game) ou de la progression des joueurs (qui constituent des aspects critiques) nécessite généralement des transactions et se révèle délicat à effectuer dans de nombreux types de bases de données distribuées.

Spanner est le premier service de base de données à cohérence forte, distribué dans le monde entier et pensé pour les entreprises. Il a été conçu pour le cloud en vue d'allier les avantages structuraux d'une base de données relationnelle à l'évolutivité horizontale non relationnelle. De nombreux éditeurs de jeux vidéo ont trouvé cette solution particulièrement adaptée pour remplacer les bases de données d'authentification et d'état de jeu dans les systèmes de production. En ajoutant des nœuds depuis la console Cloud Console, vous pouvez procéder à un scaling afin d'obtenir des performances supplémentaires ou davantage d'espace de stockage. Spanner peut gérer de manière transparente la duplication mondiale avec cohérence forte, ce qui élimine le besoin de gérer des instances dupliquées régionales.

Ce document sur les bonnes pratiques aborde les points suivants :

  • Concepts majeurs de Spanner et différences entre cette solution et les bases de données couramment utilisées dans les jeux vidéo
  • Scénarios dans lesquels Spanner constitue la base de données la plus adaptée à votre jeu
  • Schémas à éviter lors de l'utilisation de Spanner pour les jeux
  • Conception de vos opérations de base de données avec Spanner en tant que base de données de jeu
  • Modélisation des données et création d'un schéma permettant d'optimiser les performances avec Spanner

Terminologie

Droits
Jeux, extensions ou achats via une application appartenant à un joueur.
Informations personnelles
Dans les jeux, informations incluant généralement l'adresse e-mail et les données relatives au compte de paiement, telles que le numéro de carte de crédit et l'adresse de facturation. Sur certains marchés, ces informations peuvent inclure un numéro d'identification national.
Base de données de jeu
Base de données contenant la progression du joueur et son inventaire pour un jeu.
Base de données d'authentification
Base de données contenant les droits des joueurs et les informations personnelles qu'ils utilisent lors de leurs achats. La base de données d'authentification est également appelée base de données de compte ou base de données de joueur. Elle est parfois associée à la base de données de jeu, mais elle en est souvent séparée lorsque les studios ou les éditeurs exploitent plusieurs titres.
Transaction
Une transaction de base de données est un ensemble d'opérations d'écriture avec un effet "tout ou rien". Soit la transaction réussit et toutes les modifications prennent effet, soit la base de données revient à un état n'incluant aucune des modifications de la transaction. Dans les jeux, les transactions de base de données sont particulièrement importantes lors du traitement des paiements et de l'attribution de la propriété d'un inventaire ou d'une devise dans le jeu.
Système de gestion de base de données relationnelle (SGBDR)
Système de base de données basé sur des tables et des lignes qui se référencent entre elles. Les bases de données SQL Server, MySQL et, plus rarement, Oracle® sont des exemples de bases de données relationnelles utilisées pour les jeux vidéo. Ces systèmes sont fréquemment utilisés, car ils fournissent des méthodologies familières et offrent de fortes garanties pour les transactions.
Base de données NoSQL
Base de données non structurée de manière relationnelle. Ces bases de données deviennent de plus en plus populaires pour les jeux, car elles sont très flexibles lorsque le modèle de données change. MongoDB et Cassandra sont des exemples de bases de données NoSQL.
Clé primaire
Il s'agit généralement de la colonne qui contient l'ID unique pour les éléments d'inventaire, les comptes de joueur et les transactions d'achat.
Instance
Base de données unique. Par exemple, un cluster exécute plusieurs copies du logiciel de base de données, mais apparaît comme une instance unique dans le backend de jeu.
Nœud
Dans ce document, une machine unique exécutant une copie du logiciel de base de données.
Instance dupliquée
Deuxième copie d'une base de données. Les instances dupliquées sont fréquemment utilisées pour la haute disponibilité, pour récupérer les données ou pour augmenter le débit en lecture.
Cluster
Plusieurs copies du logiciel s'exécutant sur un grand nombre de machines qui, ensemble, apparaissent comme une instance unique dans le backend de jeu. Le clustering est employé pour augmenter l'évolutivité et la disponibilité.
Segment
Instance d'une base de données. De nombreux studios de jeux exécutent plusieurs instances de bases de données homogènes, chacune contenant un sous-ensemble des données de jeu. Ces instances sont généralement appelées segments. La segmentation sert généralement à améliorer les performances ou l'évolutivité, au détriment de l'efficacité de la gestion et de la simplicité des applications. La segmentation dans Spanner est mise en œuvre à l'aide de divisions.
Division
Spanner divise vos données en fragments appelés divisions. Les divisions sont indépendantes les unes des autres et peuvent être affectées à différents serveurs. Une division est une plage de lignes dans une table racine (en d'autres termes, non entrelacée), dans laquelle les lignes sont classées par clé primaire. Les clés de début et de fin de cette plage sont appelées "limites de division". Spanner ajoute et supprime automatiquement les limites de division, ce qui modifie le nombre de divisions dans la base de données. Spanner répartit les données en fonction de la charge. Il ajoute automatiquement des limites de division lorsqu'il détecte une charge de lecture ou d'écriture élevée répartie sur plusieurs clés d'une division.
Hotspot
Scénario dans lequel une division d'une base de données distribuée (telle que Spanner) contient des enregistrements qui reçoivent une grande partie des requêtes adressées à la base de données. Cette situation n'est pas souhaitable, car elle dégrade les performances.

Utiliser Spanner pour les jeux vidéo

Dans la plupart des cas où vous envisagez d'utiliser un SGBDR pour votre jeu, Spanner constitue un choix approprié, car cette solution peut remplacer efficacement la base de données de jeu, la base de données d'authentification ou, souvent, les deux.

Bases de données de jeu

Spanner peut opérer comme une autorité transactionnelle unique à l'échelle mondiale, ce qui en fait une solution idéale pour les systèmes d'inventaire de jeu. Les devises ou les éléments dans le jeu pouvant être échangés, vendus, offerts ou autrement transférés d'un joueur à un autre représente un défi pour les systèmes de jeu à grande échelle. Souvent, la popularité d'un jeu peut progresser plus rapidement que la capacité d'une base de données traditionnelle à gérer les opérations au sein d'une base de données à nœud unique. Selon le type de jeu, la base de données peut avoir du mal à identifier le nombre d'opérations requises pour gérer la charge de joueurs ainsi que la quantité de données stockées. Cela amène souvent les développeurs de jeux à segmenter leur base de données afin d'améliorer les performances, ou à stocker des tables de plus en plus grandes. Ce type de solution engendre une complexité opérationnelle et des coûts de maintenance élevés.

Pour atténuer cette complexité, une stratégie courante consiste à exécuter des régions de jeu complètement séparées, sans aucun déplacement de données possible entre elles. Dans ce cas, les joueurs ne peuvent pas échanger d'éléments ni de devises entre plusieurs régions de jeu, car les inventaires de chaque région sont stockés dans des bases de données distinctes. Toutefois, cette configuration sacrifie l'expérience de jeu au profit d'une simplicité opérationnelle et de développement.

En revanche, vous pouvez autoriser les échanges interrégionaux dans une base de données segmentée géographiquement, bien que cela augmente fortement la complexité. Cette configuration nécessite que les transactions couvrent plusieurs instances de base de données, ce qui crée une logique applicative complexe et sujette à erreur. L'utilisation de verrous de transactions sur plusieurs bases de données peut considérablement affecter les importances. En outre, le fait de ne pas pouvoir effectuer de transactions atomiques peut mener les joueurs à exploiter des failles (par exemple, dupliquer des éléments ou des devises dans le jeu), ce qui nuit à l'écosystème et à la communauté du jeu.

Spanner peut simplifier votre approche concernant les transactions d'inventaire et de devise. Même lorsque vous utilisez cette solution pour stocker toutes vos données de jeu à l'échelle mondiale, Spanner propose des transactions en lecture/écriture avec des propriétés encore plus performantes que les caractéristiques traditionnelles d'atomicité, de cohérence, d'isolation et de durabilité. Grâce à l'évolutivité de Spanner, les données n'ont pas besoin d'être segmentées en instances de base de données distinctes lorsqu'un gain de performances ou d'espace de stockage est nécessaire. Il vous suffit d'ajouter des nœuds. De plus, la haute disponibilité et la résilience des données (pour lesquelles les bases de données destinées aux jeux sont souvent soumises au clustering) sont gérées de manière transparente par Spanner, sans aucune configuration ni gestion supplémentaire.

Bases de données d'authentification

Spanner peut également s'avérer idéal pour les bases de données d'authentification, en particulier si vous souhaitez utiliser un seul SGBDR standard au niveau du studio ou de l'éditeur. Bien que les bases de données d'authentification pour les jeux n'aient généralement pas besoin d'exploiter le traitement à grande échelle de Spanner, les garanties transactionnelles et la haute disponibilité des données peuvent rendre cet aspect attrayant. La duplication de données dans Spanner est transparente, synchrone et intégrée. Spanner dispose de configurations offrant une disponibilité de 99,99 % (quatre fois le chiffre neuf) ou de 99,999 % (cinq fois le chiffre neuf), où la disponibilité de 99,999 % correspond à moins de cinq minutes et demie d'indisponibilité par an. Ce type de disponibilité en fait un choix judicieux pour le processus critique d'authentification requis au début de chaque session de jeu.

Bonnes pratiques

Cette section fournit des recommandations concernant l'utilisation de Spanner dans la conception de jeux. Il est important de modéliser vos données de jeu pour profiter des fonctionnalités uniques offertes par Spanner. Bien que vous puissiez accéder à Spanner à l'aide de la sémantique des bases de données relationnelles, certains principes relatifs à la conception de schémas peuvent vous aider à améliorer vos performances. La documentation de Spanner contient des recommandations détaillées concernant la conception de schémas que vous pouvez consulter, mais les sections suivantes fournissent quelques bonnes pratiques sur les bases de données de jeu.

Les bonnes pratiques décrites dans ce document sont basées sur des expériences tirées de l'utilisation des clients et d'études de cas.

Utiliser les UUID comme ID de joueurs et de personnages

La table des joueurs comporte généralement une ligne par joueur, qui inclut sa devise dans le jeu, sa progression ou d'autres données ne pouvant pas facilement être mappées à des lignes de table d'inventaire séparées. Si votre jeu permet aux joueurs de créer plusieurs personnages avec une progression distincte, comme c'est le cas de nombreux jeux massivement multijoueurs existants, cette table contient généralement une ligne par personnage plutôt qu'une ligne par joueur. Le schéma reste toutefois le même.

Nous vous recommandons d'utiliser un identifiant de joueur ou de personnage (ID de personnage) unique comme clé primaire de la table des personnages. Nous vous conseillons également d'exploiter l'identifiant unique universel (UUID) v4, car il répartit les données du joueur sur plusieurs nœuds de base de données et peut vous aider à optimiser les performances de Spanner.

Utiliser l'entrelacement pour les tables d'inventaire

La table d'inventaire contient souvent les éléments disponibles dans le jeu, tels que l'équipement, les cartes ou les unités d'un personnage. Généralement, un joueur dispose de nombreux éléments dans son inventaire. Chaque élément est représenté par une ligne dans la table.

Tout comme pour d'autres bases de données relationnelles, une table d'inventaire dans Spanner inclut une clé primaire, qui est un identifiant unique associé à un élément, comme illustré dans l'exemple de table suivant.

itemID type playerID
7c14887e-8d45 1 6f1ede3b-25e2
8ca83609-bb93 40 6f1ede3b-25e2
33fedada-3400 1 5fa0aa7d-16da
e4714487-075e 23 5fa0aa7d-16da
d4fbfb92-a8bd 14 5fa0aa7d-16da
31b7067b-42ec 3 26a38c2c-123a

Dans cet exemple de table d'inventaire, les valeurs itemID et playerID sont tronquées par souci de lisibilité. Une table d'inventaire réelle inclut bien d'autres colonnes qui ne sont pas fournies ici.

Dans un SGBDR, une approche typique pour le suivi de la propriété d'un élément consiste à utiliser une colonne en tant que clé étrangère contenant l'ID de joueur du propriétaire actuel. Cette colonne est la clé primaire d'une table de base de données distincte. Dans Spanner, vous pouvez recourir à l'entrelacement, qui vous permet de stocker des lignes d'inventaire à proximité de la ligne du joueur associé pour optimiser les performances. Lorsque vous utilisez des tables entrelacées, tenez compte des points suivants :

  • La taille totale des données de la ligne du joueur et de toutes ses lignes d'inventaire associées doit être inférieure à quatre Gio. Cette restriction n'est généralement pas un problème si vous disposez d'une conception de modèle de données adaptée.
  • Vous ne pouvez pas générer d'objets sans propriétaire. Si cette limitation est connue à l'avance, vous pouvez éviter les objets sans propriétaire dans la conception du jeu.

Indexer la conception pour éviter les hotspots

De nombreux développeurs de jeux mettent en œuvre des index sur un grand nombre de champs d'inventaire pour optimiser certaines requêtes. Dans Spanner, la création ou la mise à jour d'une ligne contenant des données dans cet index génère une charge d'écriture supplémentaire proportionnelle au nombre de colonnes indexées. Vous pouvez améliorer les performances de Spanner en supprimant les index rarement utilisés ou en les mettant en œuvre via une autre méthode n'affectant pas les performances de la base de données.

L'exemple suivant concerne une table qui enregistre les records des joueurs à long terme :

CREATE TABLE Ranking (
        PlayerID STRING(36) NOT NULL,
        GameMode INT64 NOT NULL,
        Score INT64 NOT NULL
) PRIMARY KEY (PlayerID, GameMode)

Cette table contient l'ID du joueur (UUIDv4), un nombre qui représente un mode de jeu, un niveau ou une saison, ainsi que le score du joueur.

Pour accélérer les requêtes qui filtrent le mode de jeu, considérons l'index suivant :

CREATE INDEX idx_score_ranking ON Ranking (
        GameMode,
        Score DESC
)

Si tout le monde joue au même mode de jeu appelé 1, cet index crée un hotspot dans lequel GameMode=1. Si vous exécutez une requête permettant d'obtenir le classement pour ce mode de jeu, l'index n'analyse que les lignes contenant GameMode=1 et renvoie rapidement le classement.

Si vous modifiez l'ordre de l'index précédent, vous pouvez résoudre ce problème de hotspot :

CREATE INDEX idx_score_ranking ON Ranking (
        Score DESC,
        GameMode
)

Cet index ne créera pas de hotspot significatif pour les joueurs participant au même mode de jeu, à condition que leurs scores soient répartis sur l'ensemble de la plage de scores. Cependant, la récupération des scores ne sera pas aussi rapide qu'avec l'index précédent, car la requête analyse tous les scores pour tous les modes pour déterminer si GameMode=1.

Ainsi, l'index réorganisé résout le problème de hotspot précédent concernant le mode de jeu, mais il peut encore être amélioré, comme illustré dans la conception suivante.

CREATE TABLE GameMode1Ranking (
        PlayerID STRING(36) NOT NULL,
        Score INT64 NOT NULL
) PRIMARY KEY (PlayerID)

CREATE INDEX idx_score_ranking ON Ranking (
        Score DESC
)

Nous vous recommandons de retirer le mode de jeu du schéma de table et d'utiliser une table par mode, si possible. Grâce à cette méthode, lorsque vous récupérez les scores d'un mode, vous n'interrogez qu'une table contenant les scores pour ce mode. Cette table peut être indexée par score pour permettre une récupération rapide des plages de scores, sans impliquer un risque élevé d'obtenir des hotspots (à condition que les scores soient bien répartis). Au moment de la rédaction de ce document, le nombre maximal de tables par base de données dans Spanner est de 2 560, ce qui est largement suffisant pour la plupart des jeux.

Séparer les bases de données par locataire

Contrairement à d'autres charges de travail, pour lesquelles nous vous recommandons de concevoir une architecture mutualisée dans Spanner en utilisant différentes valeurs de clé primaire, nous vous conseillons, pour les données de jeu, de suivre l'approche plus traditionnelle consistant à séparer les bases de données par locataire. Les modifications de schéma sont courantes lors du lancement de nouvelles fonctionnalités dans les jeux faisant l'objet d'un service en temps réel. L'isolation des locataires au niveau de la base de données peut ainsi simplifier les mises à jour de schéma. Cette stratégie permet également d'optimiser le temps nécessaire à la sauvegarde ou à la restauration des données d'un locataire, car ces opérations sont effectuées simultanément sur l'ensemble d'une base de données.

Éviter les mises à jour de schéma incrémentielles

Contrairement à certaines bases de données relationnelles classiques, Spanner reste opérationnel pendant les mises à jour de schéma. Toutes les requêtes exécutées sur l'ancien schéma sont renvoyées (même si elles sont renvoyées moins rapidement que d'habitude), tandis que les requêtes adressées au nouveau schéma sont renvoyées dès qu'elles sont disponibles. Vous pouvez concevoir votre propre processus de mise à jour pour vous assurer que votre jeu reste disponible pendant les mises à jour de schéma à l'aide de Spanner, à condition de respecter les contraintes précédentes.

Toutefois, si vous demandez une autre modification de schéma lorsqu'une modification est déjà en cours de traitement, la nouvelle modification est mise en file d'attente et n'est traitée qu'une fois toutes les mises à jour de schéma précédentes terminées. Vous pouvez éviter cette situation en programmant des mises à jour de schéma plus étendues au lieu de demander un grand nombre de mises à jour incrémentielles sur une courte période. Pour en savoir plus sur les mises à jour de schéma, y compris sur la façon d'effectuer une mise à jour de schéma nécessitant la validation de données, consultez la documentation de mise à jour des schémas Spanner.

Réfléchir à l'accès à la base de données et à sa taille

Lorsque vous développez votre serveur de jeu et vos services de plate-forme pour qu'ils utilisent Spanner, réfléchissez à la manière dont votre jeu accédera à la base de données et à la façon dont vous la dimensionnerez afin d'éviter les coûts inutiles.

Utiliser des pilotes et des bibliothèques natifs

Lorsque vous développez vos services à l'aide de Spanner, réfléchissez à la façon dont votre code communique avec la base de données. Spanner propose des bibliothèques clientes natives pour plusieurs langages populaires, qui sont généralement riches en fonctionnalités et performantes. Des pilotes JDBC compatibles avec les instructions LMD (langage de manipulation de données) et LDD (langage de définition de données) sont également disponibles. Dans les cas où Spanner est utilisé dans un nouveau développement, nous vous recommandons d'exploiter les bibliothèques clientes cloud pour Spanner. Bien que les intégrations de moteur de jeu classiques ne fournissent pas une sélection du langage étendue, certains clients de jeux utilisent Java ou Go pour les services de plate-forme qui accèdent à Spanner. Pour les applications haut débit, sélectionnez une bibliothèque qui vous permet d'utiliser le même client Spanner pour plusieurs requêtes séquentielles.

Dimensionner la base de données en fonction des besoins de test et de production

Au cours de la phase de développement, une instance Spanner à nœud unique suffit probablement à effectuer la plupart des activités, y compris les tests fonctionnels.

Évaluer vos besoins Spanner pour la production

Lorsque vous passez du développement au test, puis à la production, il est important de réévaluer vos besoins Spanner pour vous assurer que votre jeu pourra gérer le trafic de joueurs en temps réel.

Avant de passer à l'environnement de production, l'exécution de tests de charge est essentielle pour vérifier que votre backend pourra gérer la charge en production. Nous vous recommandons d'effectuer les tests de charge en spécifiant une charge deux fois supérieure à celle attendue en production. Ainsi, vous serez prêts à faire face aux pics d'utilisation et à gérer le trafic si votre jeu se révèle plus populaire que prévu.

Exécuter les tests de charge avec des données réelles

L'exécution d'un test de charge à l'aide de données synthétiques ne suffit pas. Vous devez aussi effectuer des tests de charge en utilisant des données et des schémas d'accès le plus proche possible de ceux attendus en production. Les données synthétiques peuvent ne pas détecter les éventuels hotspots dans la conception de votre schéma Spanner. Pour vérifier le comportement de Spanner avec des données réelles, rien ne vaut le lancement d'un test bêta (ouvert ou fermé) avec de vrais joueurs.

Le diagramme suivant est un exemple de schéma de table de joueurs provenant d'un studio de jeux. Il démontre l'importance des tests bêta pour les tests de charge.

Liste des noms de joueurs et attribut pour les tests de charge.

Le studio a préparé ces données représentatives basées sur les tendances d'un jeu qu'il a géré pendant deux ans. Il s'attendait à ce que le schéma représente efficacement les données dans ce nouveau jeu.

Chaque enregistrement est associé à des attributs numériques qui suivent la progression du joueur au sein du jeu (classement, temps de jeu, etc.). Pour l'exemple d'attribut utilisé dans la table ci-dessus, chaque nouveau joueur débute avec la valeur 50, puis celle-ci varie entre 1 et 100 au fil de sa progression.

Le studio souhaite indexer cet attribut afin d'accélérer les requêtes importantes pendant le jeu.

À partir de ces données, le studio a créé la table Spanner suivante, qui comprend une clé primaire correspondant à l'ID du joueur (PlayerID) ainsi qu'un index secondaire pour l'attribut (Attribute).

CREATE TABLE Player (
        PlayerID STRING(36) NOT NULL,
        Attribute INT64 NOT NULL
) PRIMARY KEY (PlayerID)

CREATE INDEX idx_attribute ON Player(Attribute)

Le studio a ensuite interrogé l'index afin d'identifier un maximum de 10 joueurs pour lesquels Attribute=23 :

SELECT PlayerID
        FROM Player@{force_index=idx_attribute}
        WHERE Attribute = 23
        LIMIT 10

D'après la documentation sur l'optimisation de la conception de schéma, Spanner stocke les données d'index de la même manière qu'il stocke des tables, avec une ligne par entrée d'index. Lors des tests de charge, ce modèle répartit de façon satisfaisante les charges de lecture et d'écriture sur plusieurs divisions Spanner, comme illustré dans le schéma suivant :

Joueurs répartis sur les divisions Spanner en fonction de leur attribut.

Bien que les données synthétiques utilisées dans le test de charge soient semblables à l'état stable final du jeu (où les valeurs Attribute sont bien distribuées), la conception du jeu spécifie que tous les nouveaux joueurs débutent avec Attribute=50. Comme chaque joueur commence avec Attribute=50, les nouveaux membres sont ajoutés à la même partie de l'index secondaire idx_attribute. Cela signifie que les modifications parviennent à la même division Spanner, ce qui crée un hotspot pendant la période de lancement du jeu. Cette utilisation de Spanner n'est pas efficace.

Joueurs ayant le même attribut au lancement, ce qui crée un hotspot dans une division Spanner.

En ajoutant une colonne IndexPartition au schéma après le lancement, le problème de hotspot est résolu et les joueurs sont répartis équitablement entre les divisions Spanner disponibles. La nouvelle commande permettant de créer la table et l'index se présente comme suit :

CREATE TABLE Player (
        PlayerID STRING(36) NOT NULL,
        IndexPartition INT64 NOT NULL
        Attribute INT64 NOT NULL
) PRIMARY KEY (PlayerID)

CREATE INDEX idx_attribute ON Player(IndexPartition,Attribute)

L'ajout d'une colonne IndexPartition au schéma répartit équitablement les joueurs au lancement.

La valeur IndexPartition doit être associée à une plage limitée pour permettre une interrogation efficace, mais cette plage doit également être au moins deux fois supérieure au nombre de divisions pour que la répartition soit performante.

Ici, le studio a manuellement attribué à chaque joueur une valeur IndexPartition comprise entre 1 et 6 dans l'application de jeu.

Vous pourriez également attribuer un nombre aléatoire à chaque joueur, ou encore assigner une valeur dérivée d'un hachage de la valeur PlayerID. Pour découvrir d'autres stratégies de segmentation au niveau de l'application, consultez l'article What DBAs need to know about Cloud Spanner, part 1: Keys and indexes (Ce que les administrateurs de base de données doivent savoir sur Cloud Spanner, partie 1 : Clés et index).

Une fois la requête précédente modifiée afin d'utiliser l'index amélioré, elle se présente comme suit :

SELECT PlayerID
        FROM Player@{force_index=idx_attribute}
        WHERE IndexPartition BETWEEN 1 and 6
        AND Attribute = 23
        LIMIT 10

Comme aucun test bêta n'a été mis en œuvre, le studio ne s'est pas rendu compte qu'il effectuait des tests à partir de données comportant des hypothèses incorrectes. Bien que les tests de charge synthétiques permettent de déterminer combien de requêtes par seconde (RPS) votre instance peut traiter, la mise en œuvre d'un test bêta est nécessaire pour valider votre schéma et réussir le lancement de votre jeu.

Dimensionner l'environnement de production afin d'anticiper les pics de demande

Le pic de trafic des jeux à succès se produit généralement à leur lancement. La conception d'un backend évolutif ne s'applique pas qu'aux services de plate-forme et aux serveurs de jeu dédiés, mais également aux bases de données. Grâce à des solutions Google Cloud telles qu'App Engine, vous pouvez développer des services d'API frontend qui effectuent un scaling rapide. Bien que Spanner vous permette d'ajouter et de supprimer des nœuds en ligne, il ne s'agit pas d'une base de données avec autoscaling. Vous devez provisionner suffisamment de nœuds pour gérer le pic de trafic qui survient au lancement.

En fonction des données recueillies lors des tests de charge ou des tests bêta publics, vous pouvez estimer le nombre de nœuds requis pour traiter les requêtes au lancement. Il est judicieux d'ajouter quelques nœuds en tant que mémoire tampon au cas où vous auriez plus de joueurs que prévu. Vous devriez toujours dimensionner la base de données pour ne pas dépasser une utilisation moyenne du processeur de 65 %.

Préchauffer la base de données avant le lancement

Un autre aspect à prendre en compte avant le lancement est le préchauffage de la base de données.

Spanner à l'état froid ne peut pas vous fournir les nœuds dont vous avez besoin pour le lancement. Vous devez d'abord passer le service à l'état chaud.

Spanner est une base de données distribuée. Cela signifie qu'à mesure que votre base de données s'agrandit, Spanner divise vos données en fragments appelés "divisions". Les divisions sont indépendantes les unes des autres et peuvent être affectées à différents serveurs pouvant être situés dans différents emplacements physiques. Pour en savoir plus, consultez la section Divisions de base de données.

Une division est définie comme une plage de lignes. En d'autres termes, elle contient un sous-ensemble de votre table. Spanner répartit les données en fonction de la charge et de leur taille. Ainsi, les divisions peuvent être déplacées de manière dynamique entre les nœuds Spanner afin d'équilibrer la charge globale de la base de données. Plus vous insérez de données dans Spanner, plus le nombre de divisions générées est grand.

Le schéma suivant montre quatre nœuds.

Données dans un nœud lorsque Spanner est à l'état froid.

Comme vous ne disposez d'aucune donnée dans Spanner, lorsque vous commencez à écrire des données, vous n'écrivez que sur un seul nœud. Spanner est actuellement à l'état froid.

Le schéma suivant illustre la répartition entre les différents nœuds.

Données réparties entre les nœuds lorsque Spanner est à l'état chaud.

À mesure que les données parviennent au système, Spanner commence à les répartir pour rééquilibrer la charge entre les quatre nœuds provisionnés. Spanner est désormais à l'état chaud.

Avant de lancer votre jeu, veillez à ce que Spanner soit à l'état chaud et que les divisions soient réparties sur l'ensemble des nœuds. Pour passer votre base de données à l'état chaud, procédez comme suit :

  1. Assurez-vous que les clés primaires de table que vous générez pour votre test de charge se trouvent dans le même espace de clés (qu'elles possèdent les mêmes propriétés statistiques) que les clés que vous utilisez pour le trafic de production réel.
  2. Effectuez un test de charge deux jours avant votre lancement. Exécutez le test de charge pendant au moins une heure en spécifiant le pic de charge attendu. Le test de charge amène Spanner à créer davantage de divisions en raison de la répartition basée sur la charge.
  3. Une fois le test de charge terminé, vous pouvez supprimer les lignes générées dans les tables par votre test de charge, en veillant à ne pas supprimer les tables elles-mêmes. Ainsi, les divisions seront disponibles pour votre période de lancement.

Surveiller et comprendre les performances

Toute base de données de production nécessite des métriques de surveillance et de performances complètes. Spanner intègre des métriques dans Cloud Monitoring. Lorsque c'est possible, nous vous recommandons d'ajouter les bibliothèques gRPC fournies à votre processus backend de jeu, car elles incluent le traçage OpenCensus. Cette fonctionnalité vous permet de visualiser les traces des requêtes dans Cloud Trace ainsi que d'autres outils de traçage Open Source compatibles.

Dans Cloud Monitoring, vous pouvez afficher les détails de votre utilisation de Spanner, y compris le stockage des données et l'utilisation du processeur. Dans la plupart des cas, nous vous recommandons de baser vos décisions concernant le scaling de Spanner sur la métrique d'utilisation du processeur ou sur la latence observée. Pour en savoir plus sur l'utilisation de processeur recommandée afin d'optimiser les performances, consultez les bonnes pratiques relatives aux instances.

Spanner propose des plans d'exécution des requêtes. Vous pouvez consulter ces plans dans Cloud Console et contacter l'assistance si vous avez besoin d'aide pour interpréter les performances de vos requêtes.

Lorsque vous évaluez les performances, réduisez au minimum les tests à cycle court, car Spanner répartit vos données en arrière-plan de façon transparente pour optimiser les performances en fonction de vos modèles d'accès aux données. Évaluez plutôt les performances en utilisant des charges de requêtes prolongées et réalistes.

Lorsque vous supprimez des données, supprimez des lignes plutôt que de recréer des tables

Dans Spanner, les tables nouvellement créées n'ont pas encore été soumises à une répartition en fonction de la charge ou de la taille en vue d'améliorer les performances. Lorsque vous supprimez des données en supprimant une table, puis en la recréant, Spanner doit utiliser des données, des requêtes et du temps pour déterminer les divisions qui conviennent à votre table. Si vous prévoyez d'utiliser à nouveau le même type de données dans une table (par exemple, lorsque vous effectuez des tests de performance consécutifs), vous pouvez exécuter une requête DELETE sur les lignes qui contiennent les données dont vous n'avez plus besoin. Pour la même raison, les mises à jour de schéma doivent exploiter l'API Cloud Spanner fournie et éviter toute stratégie manuelle, telle que la création d'une table ou la copie de données à partir d'une autre table ou d'un fichier de sauvegarde.

Choisir un emplacement de données répondant aux exigences de conformité

De nombreux jeux doivent être conformes aux législations relatives à l'emplacement des données telles que le RGPD lorsqu'ils sont disponibles dans le monde entier. Pour vous aider à répondre aux exigences liées au RGPD, consultez le livre blanc sur le RGPD pour Google Cloud et sélectionnez la configuration régionale Spanner appropriée.

Étapes suivantes