Bonnes pratiques pour le chargement groupé

Cette page fournit des instructions pour effectuer un chargement groupé efficace de grandes quantités de données dans Spanner.

Plusieurs options s'offrent à vous pour charger des données de manière groupée dans Spanner:

Bien que vous puissiez également insérer des lignes à l'aide de Google Cloud CLI, nous vous déconseillons d'utiliser la gcloud CLI pour le chargement groupé.

Consignes relatives aux performances pour le chargement groupé

Pour optimiser les performances de chargement groupé, optimisez votre utilisation du partitionnement afin de répartir l'écriture des données entre les tâches de nœud de calcul.

Spanner utilise la répartition basée sur la charge pour répartir uniformément la charge des données entre les ressources de calcul de l'instance. Après quelques minutes avec une charge élevée, Spanner introduit des limites de division entre les lignes. En règle générale, si votre charge de données est bien distribuée et que vous suivez les bonnes pratiques relatives à la conception de schémas et au chargement groupé, votre débit en écriture devrait doubler toutes les quelques minutes jusqu'à ce que les ressources de processeur de l'instance soient saturées.

Partitionner les données par clé primaire

Spanner partitionne les tables de manière dynamique en plages plus petites. La clé primaire d'une ligne détermine son emplacement.

Pour obtenir un débit en écriture optimal pour les chargements groupés, partitionnez vos données par clé primaire selon ce modèle :

  • Chaque partition contient une plage de lignes consécutives, déterminée par les colonnes de clé.
  • Chaque commit contient des données pour une seule partition.

Nous vous recommandons de définir un nombre de partitions 10 fois supérieur au nombre de nœuds de votre instance Spanner. Pour affecter des lignes aux partitions, procédez comme suit :

  • Triez vos données par clé primaire.
  • Divisez les données en 10 * (nombre de nœuds) partitions distinctes de taille égale.
  • Créez et affectez une tâche de nœud de calcul distincte à chaque partition. La création des tâches de nœud de calcul s'effectue dans votre application. Il ne s'agit pas d'une fonctionnalité de Spanner.

En suivant ce schéma, vous devriez constater un débit en écriture groupé global atteignant jusqu'à 10 à 20 Mo par seconde par nœud pour les charges importantes.

Lorsque vous chargez des données, Spanner crée et met à jour des divisions pour équilibrer la charge sur les nœuds de votre instance. Pendant ce processus, des baisses temporaires du débit peuvent survenir.

Exemple

Vous avez une configuration régionale avec trois nœuds. Vous disposez d'une table non entrelacée contenant 90 000 lignes. Les clés primaires de la table vont de 1 à 90 000.

  • Lignes : 90 000
  • Nœuds : 3
  • Partitions : 10 * 3 = 30
  • Lignes par partition : 90 000 / 30 = 3 000.

La première partition comprend la plage de clés 1 à 3 000. La deuxième partition comprend la plage de clés 3 001 à 6 000. La 30e partition comprend la plage de clés 87 001 à 90 000. (Il est déconseillé d'utiliser des clés séquentielles dans une grande table. Cet exemple n'est présenté qu'à des fins de démonstration.)

Chaque tâche de nœud de calcul envoie les écritures pour une partition. Dans chaque partition, vous devez écrire les lignes de manière séquentielle par clé primaire. L'écriture aléatoire de lignes en fonction de la clé primaire devrait également fournir un débit raisonnablement élevé. Vous pouvez exécuter des tests pour déterminer l'approche offrant les meilleures performances pour votre ensemble de données.

Si vous décidez de ne pas utiliser de partitions

L'écriture de lignes aléatoires dans un commit peut être plus lente que l'écriture d'un ensemble contigu de lignes dans un commit, et peut être amené à toucher des données dans différentes partitions. La latence et la surcharge des commits sont plus élevés lorsque davantage de divisions sont écrites dans un commit, en raison d'une meilleure coordination entre les serveurs. Plusieurs divisions sont probablement impliquées, car chaque ligne aléatoire peut appartenir à une division différente. Dans le pire des cas, chaque écriture implique toutes les divisions de votre instance Spanner. Comme mentionné ci-dessus, le débit en écriture est réduit lorsque davantage de divisions sont impliquées.

Charger de manière groupée sans partitionnement

Il peut être plus rapide d'écrire un ensemble de lignes contiguës dans un commit que d'écrire des lignes aléatoires. Les lignes aléatoires incluent également probablement des données provenant de différentes partitions.

Lorsque davantage de partitions sont écrites dans un commit, une plus grande coordination entre les serveurs est requise, ce qui augmente la latence et la surcharge de commit.

Plusieurs partitions sont probablement impliquées, car chaque ligne aléatoire peut appartenir à une partition différente. Dans le pire des cas, chaque écriture implique chaque partition de votre instance Spanner. Comme indiqué ci-dessus, le débit en écriture est réduit lorsque davantage de partitions sont impliquées.

Éviter la surcharge

Il est possible d'envoyer plus de requêtes d'écriture que Spanner ne peut en gérer. Spanner gère la surcharge en annulant les transactions. Ce processus est appelé "réponse". Pour les transactions en écriture seule, Spanner relance automatiquement la transaction. Dans ce cas, le refus de transaction se traduit par une latence élevée. Lors de charges importantes, ce phénomène peut durer jusqu'à une minute. Lors de charges extrêmement lourdes, il peut durer plusieurs minutes. Pour éviter les refus de transaction, il est conseillé de limiter les requêtes d'écriture afin de maintenir l'utilisation du processeur dans des limites raisonnables. Les utilisateurs peuvent également augmenter le nombre de nœuds afin que l'utilisation du processeur ne dépasse pas les limites.

Commit entre 1 et 5 Mo de mutations à la fois

Chaque écriture dans Spanner entraîne une surcharge, que l'écriture soit volumineuse ou non. Pour optimiser le débit, optimisez la quantité de données stockées par écriture. Les écritures de grande taille réduisent le ratio de surcharge par écriture. Une bonne technique consiste à appliquer des commits mutant des centaines de lignes. Lors de l'écriture de lignes relativement grandes, une taille de commit comprise entre 1 et 5 Mo offre généralement des performances optimales. Lors de l'écriture de petites valeurs ou de valeurs indexées, il est généralement préférable d'écrire au plus quelques centaines de lignes dans un même commit. Indépendamment de la taille de commit et du nombre de lignes, sachez qu'il existe une limite de 80 000 mutations par commit. Pour déterminer les performances optimales, vous devez tester et mesurer le débit.

Les commits de plus de 5 Mo ou de plus de quelques centaines de lignes n'offrent pas d'avantages supplémentaires et risquent de dépasser les limites de Spanner en termes de taille de commit et de nombre de mutations par commit.

Consignes relatives aux index secondaires

Si votre base de données contient des index secondaires, vous devez choisir d'ajouter les index au schéma de base de données avant ou après le chargement des données de la table.

  • L'ajout de l'index avant le chargement des données permet de terminer immédiatement la modification du schéma. Cependant, chaque écriture affectant l'index prend plus de temps, car il doit également mettre à jour l'index. Une fois le chargement des données terminé, la base de données est immédiatement utilisable avec tous les index en place. Pour créer une table et ses index en même temps, envoyez les instructions LDD pour la nouvelle table et les nouveaux index en une seule requête à Spanner.

  • L'ajout de l'index après le chargement des données signifie que chaque écriture est efficace. Cependant, la modification du schéma de chaque remplissage de l'index peut prendre beaucoup de temps. La base de données n'est pas entièrement utilisable, et les requêtes ne peuvent pas utiliser les index tant que toutes les modifications de schéma ne sont pas terminées. La base de données peut toujours diffuser les écritures et les requêtes, mais à un débit plus lent.

Nous vous recommandons d'ajouter des index essentiels à votre application métier avant de charger les données. Pour tous les index non critiques, ajoutez-les après la migration des données.

Tester et mesurer le débit

Il peut s'avérer difficile de prédire le débit. C'est pourquoi nous vous recommandons de tester votre stratégie de chargement groupé avant d'exécuter le chargement final. Pour obtenir un exemple détaillé d'utilisation du partitionnement et de surveillance des performances, consultez la page relative à l'optimisation du débit de chargement de données.

Bonnes pratiques relatives au chargement groupé périodique dans une base de données existante

Si vous mettez à jour une base de données existante contenant des données, mais ne disposant d'aucun index secondaire, les recommandations décrites sur cette page s'appliquent toujours.

Si vous disposez d'index secondaires, ces instructions peuvent quand même conduire à des performances raisonnables. Celles-ci dépendent du nombre moyen de divisions impliquées dans vos transactions. Si le débit est trop faible, vous pouvez essayer les solutions suivantes :

  • Incluez moins de mutations dans chaque commit pour tenter d'augmenter le débit.
  • Si la taille de l'importation est supérieure à la taille totale actuelle de la table mise à jour, supprimez les index secondaires, puis rajoutez-les une fois l'opération terminée. Cette étape n'est généralement pas indispensable, mais elle peut améliorer le débit.