Recherche de site Web

Comprendre le sharding de bases de données


Introduction

Toute application ou site web qui connaît une croissance significative devra éventuellement évoluer afin de s'adapter à l'augmentation du trafic. Pour les applications et sites web axés sur les données, il est crucial que l'évolution se fasse de manière à garantir la sécurité et l'intégrité de leurs données. Il peut être difficile de prédire la popularité qu'un site web ou une application atteindra ou combien de temps il maintiendra cette popularité, c'est pourquoi certaines organisations choisissent une architecture de base de données qui leur permet de faire évoluer leurs bases de données de manière dynamique.

Dans cet article conceptuel, nous discuterons d'une telle architecture de base de données : les bases de données shardées. Le sharding a attiré beaucoup d'attention ces dernières années, mais beaucoup de personnes n'ont pas une compréhension claire de ce que c'est ni des scénarios dans lesquels il pourrait être judicieux de sharder une base de données. Nous passerons en revue ce qu'est le sharding, certains de ses principaux avantages et inconvénients, ainsi que quelques méthodes de sharding courantes.

Qu'est-ce que le Sharding ?

Le sharding est un modèle d'architecture de base de données lié à la partition horizontale — la pratique consistant à séparer les lignes d'une table en plusieurs tables différentes, appelées partitions. Chaque partition possède le même schéma et les mêmes colonnes, mais également des lignes totalement différentes. De même, les données contenues dans chacune sont uniques et indépendantes des données contenues dans les autres partitions.

Il peut être utile de penser au partitionnement horizontal en termes de sa relation avec le partitionnement vertical. Dans une table partitionnée verticalement, des colonnes entières sont séparées et placées dans de nouvelles tables distinctes. Les données contenues dans une partition verticale sont indépendantes des données de toutes les autres, et chacune contient à la fois des lignes et des colonnes distinctes. Le diagramme suivant illustre comment une table pourrait être partitionnée à la fois horizontalement et verticalement :

Le sharding consiste à diviser ses données en deux ou plusieurs morceaux plus petits, appelés shards logiques. Les shards logiques sont ensuite répartis sur différents nœuds de base de données, appelés shards physiques, qui peuvent contenir plusieurs shards logiques. Malgré cela, les données contenues dans tous les shards représentent collectivement un ensemble logique complet de données.

Les fragments de base de données illustrent une architecture sans partage. Cela signifie que les fragments sont autonomes ; ils ne partagent aucune donnée ni ressource informatique. Dans certains cas, toutefois, il peut être judicieux de répliquer certaines tables dans chaque fragment pour servir de tables de référence. Par exemple, supposons qu’il existe une base de données pour une application qui dépend de taux de conversion fixes pour les mesures de poids. En répliquant une table contenant les données de taux de conversion nécessaires dans chaque fragment, cela aiderait à garantir que toutes les données requises pour les requêtes sont présentes dans chaque fragment.

Souvent, le sharding est mis en œuvre au niveau de l'application, ce qui signifie que l'application inclut du code qui définit vers quel shard transmettre les lectures et les écritures. Cependant, certains systèmes de gestion de bases de données ont des capacités de sharding intégrées, ce qui permet de mettre en œuvre le sharding directement au niveau de la base de données.

Étant donné cet aperçu général du sharding, passons en revue certains des aspects positifs et négatifs associés à cette architecture de base de données.

Avantages du sharding

L'attraction principale du sharding d'une base de données est qu'il peut aider à faciliter le scaling horizontal, également connu sous le nom de scaling out. Le scaling horizontal est la pratique d'ajouter plus de machines à une infrastructure existante afin de répartir la charge et de permettre plus de trafic et un traitement plus rapide. Cela est souvent mis en contraste avec le scaling vertical, autrement connu sous le nom de scaling up, qui consiste à mettre à niveau le matériel d'un serveur existant, généralement en ajoutant plus de RAM ou de CPU.

Il est relativement simple de faire fonctionner une base de données relationnelle sur une seule machine et de l'augmenter si nécessaire en améliorant ses ressources informatiques. Cependant, en fin de compte, toute base de données non distribuée sera limitée en termes de stockage et de puissance de calcul, donc avoir la possibilité de scaler horizontalement rend votre configuration beaucoup plus flexible.

Une autre raison pour laquelle certains pourraient choisir une architecture de base de données segmentée est d’accélérer les temps de réponse des requêtes. Lorsque vous soumettez une requête sur une base de données qui n’a pas été segmentée, elle peut devoir parcourir chaque ligne de la table que vous interrogez avant de pouvoir trouver l’ensemble de résultats que vous recherchez. Pour une application avec une grande base de données monolithique, les requêtes peuvent devenir extrêmement lentes. En segmentant toutefois une table en plusieurs, les requêtes doivent parcourir moins de lignes et leurs ensembles de résultats sont renvoyés beaucoup plus rapidement.

Le sharding peut également aider à rendre une application plus fiable en atténuant l'impact des pannes. Si votre application ou site web dépend d'une base de données non shardée, une panne pourrait rendre l'ensemble de l'application indisponible. Avec une base de données sharded, cependant, une panne n'affecterait probablement qu'un seul shard. Même si cela pourrait rendre certaines parties de l'application ou du site web indisponibles pour certains utilisateurs, l'impact global serait quand même moindre que si la base de données entière tombait en panne.

Inconvénients du sharding

Bien que le sharding d'une base de données puisse faciliter la montée en charge et améliorer les performances, il peut également imposer certaines limites. Ici, nous discuterons de certaines de celles-ci et des raisons pour lesquelles elles pourraient inciter à éviter complètement le sharding.

La première difficulté que les gens rencontrent avec le sharding est la complexité pure de la mise en œuvre correcte d'une architecture de base de données shardée. Si cela est mal fait, il existe un risque important que le processus de sharding entraîne une perte de données ou des tables corrompues. Même lorsqu'il est correctement effectué, le sharding est susceptible d'avoir un impact majeur sur les flux de travail de votre équipe. Au lieu d'accéder et de gérer ses données depuis un point d'entrée unique, les utilisateurs doivent gérer les données à travers plusieurs emplacements de shards, ce qui pourrait potentiellement perturber certaines équipes.

Un problème que les utilisateurs rencontrent parfois après avoir fragmenté une base de données est que les fragments finissent par devenir déséquilibrés. À titre d'exemple, supposons que vous ayez une base de données avec deux fragments distincts, l'un pour les clients dont le nom de famille commence par les lettres A à M et l'autre pour ceux dont le nom commence par les lettres N à Z. Cependant, votre application dessert un nombre disproportionné de personnes dont le nom de famille commence par la lettre G. En conséquence, le fragment A-M accumule progressivement plus de données que le fragment N-Z, ce qui provoque un ralentissement et des blocages pour une partie significative de vos utilisateurs. Le fragment A-M est devenu ce que l'on appelle un point chaud de la base de données. Dans ce cas, tout avantage de la fragmentation de la base de données est annulé par les ralentissements et les crashs. La base de données devrait probablement être réparée et re-fragmentée pour permettre une répartition des données plus équilibrée.

Un autre inconvénient majeur est qu'une fois qu'une base de données a été fragmentée, il peut être très difficile de la ramener à son architecture non fragmentée. Toutes les sauvegardes de la base de données effectuées avant sa fragmentation n’incluront pas les données écrites depuis la partition. Par conséquent, reconstruire l’architecture originale non fragmentée nécessiterait de fusionner les nouvelles données partitionnées avec les anciennes sauvegardes ou, alternativement, de transformer la base de données partitionnée en une seule base de données, ce qui serait dans les deux cas coûteux et chronophage.

Un dernier inconvénient à considérer est que le sharding n'est pas pris en charge nativement par tous les moteurs de base de données. Par exemple, PostgreSQL n'inclut pas le sharding automatique comme fonctionnalité, bien qu'il soit possible de partitionner manuellement une base de données PostgreSQL. Il existe un certain nombre de forks de Postgres qui incluent le sharding automatique, mais ceux-ci suivent souvent en retard la dernière version de PostgreSQL et manquent de certaines autres fonctionnalités. Certaines technologies de base de données spécialisées — comme MySQL Cluster ou certains produits de base de données en tant que service comme MongoDB Atlas — incluent le sharding automatique en tant que fonctionnalité, mais les versions « vanille » de ces systèmes de gestion de bases de données ne le font pas. Pour cette raison, le sharding nécessite souvent une approche de « faites-le vous-même ». Cela signifie que la documentation sur le sharding ou les conseils pour résoudre les problèmes sont souvent difficiles à trouver.

Ce ne sont, bien sûr, que quelques problèmes généraux à considérer avant le partitionnement. Il peut y avoir beaucoup d'autres inconvénients potentiels à partitionner une base de données selon son cas d'utilisation.

Maintenant que nous avons couvert quelques inconvénients et avantages du sharding, nous allons passer en revue quelques architectures différentes pour les bases de données shardées.

Architectures de sharding

Une fois que vous avez décidé de fragmenter votre base de données, la prochaine étape consiste à déterminer comment vous allez le faire. Lors de l'exécution de requêtes ou de la distribution de données entrantes vers des tables ou bases de données fragmentées, il est crucial que celles-ci aillent dans le fragment correct. Sinon, cela pourrait entraîner une perte de données ou des requêtes extrêmement lentes. Dans cette section, nous passerons en revue quelques architectures de fragmentation courantes, chacune utilisant un processus légèrement différent pour distribuer les données entre les fragments.

Partitionnement basé sur les clés

Sharding basé sur la clé, également connu sous le nom de sharding basé sur le hash, consiste à utiliser une valeur provenant des nouvelles données écrites — comme le numéro d'identification d'un client, l'adresse IP d'une application cliente, un code postal, etc. — et à la placer dans une fonction de hash pour déterminer dans quel shard les données doivent être stockées. Une fonction de hash est une fonction qui prend en entrée un morceau de données (par exemple, un email de client) et produit une valeur discrète, connue sous le nom de valeur de hash. Dans le cas du sharding, la valeur de hash est un ID de shard utilisé pour déterminer sur quel shard les données entrantes seront stockées. Dans l'ensemble, le processus se présente comme suit :

Pour garantir que les entrées sont placées dans les fragments corrects et de manière cohérente, les valeurs saisies dans la fonction de hachage doivent toutes provenir de la même colonne. Cette colonne est connue sous le nom de clé de fragment. En termes simples, les clés de fragment sont similaires aux clés primaires en ce sens que les deux sont des colonnes utilisées pour établir un identifiant unique pour chaque ligne. De manière générale, une clé de fragment devrait être statique, c’est-à-dire qu’elle ne devrait pas contenir de valeurs susceptibles de changer au fil du temps. Sinon, cela augmenterait la quantité de travail nécessaire pour les opérations de mise à jour et pourrait ralentir les performances.

Bien que le sharding basé sur les clés soit une architecture de sharding assez courante, cela peut compliquer les choses lorsqu'on essaie d'ajouter ou de retirer dynamiquement des serveurs supplémentaires à une base de données. Lorsque vous ajoutez des serveurs, chacun aura besoin d'une valeur de hachage correspondante et de nombreuses entrées existantes, sinon toutes, devront être réaffectées à leur nouvelle valeur de hachage correcte, puis migrées vers le serveur approprié. À mesure que vous commencez à rééquilibrer les données, ni les nouvelles fonctions de hachage ni les anciennes ne seront valides. Par conséquent, votre serveur ne pourra pas écrire de nouvelles données pendant la migration et votre application pourrait subir des interruptions.

L'attrait principal de cette stratégie est qu'elle peut être utilisée pour répartir les données de manière uniforme afin d'éviter les points chauds. De plus, comme elle distribue les données de manière algorithmique, il n'est pas nécessaire de maintenir une carte indiquant où toutes les données sont situées, comme c'est le cas avec d'autres stratégies telles que le sharding basé sur les plages ou les répertoires.

Partitionnement basé sur les plages

Sharding basé sur les plages consiste à fragmenter les données en fonction des plages d'une valeur donnée. Pour illustrer, disons que vous avez une base de données qui stocke des informations sur tous les produits dans le catalogue d'un détaillant. Vous pourriez créer quelques fragments différents et répartir les informations de chaque produit en fonction de la plage de prix dans laquelle ils se trouvent, comme ceci :

Le principal avantage du sharding basé sur des plages est qu'il est relativement simple à mettre en œuvre. Chaque fragment contient un ensemble de données différent, mais tous ont un schéma identique les uns aux autres, ainsi qu'à la base de données originale. Le code de l'application lit dans quelle plage les données se situent et les écrit dans le fragment correspondant.

D'un autre côté, le sharding basé sur les plages ne protège pas les données contre une distribution inégale, ce qui conduit aux points chauds de base de données mentionnés précédemment. En regardant le diagramme d'exemple, même si chaque shard contient une quantité égale de données, il est probable que certains produits reçoivent plus d'attention que d'autres. Leurs shards respectifs recevront, à leur tour, un nombre disproportionné de lectures.

Fragmentation basée sur un répertoire

Pour mettre en œuvre le sharding basé sur un répertoire, il faut créer et maintenir un tableau de correspondance qui utilise une clé de shard pour suivre quel shard contient quelles données. Un tableau de correspondance est un tableau qui contient un ensemble statique d'informations sur l'emplacement où des données spécifiques peuvent être trouvées. Le diagramme suivant montre un exemple simplifié de sharding basé sur un répertoire :

Ici, la colonne Delivery Zone est définie comme une clé de fragment. Les données de la clé de fragment sont écrites dans la table de correspondance en même temps que le fragment auquel chaque ligne respective doit être écrite. Cela est similaire au partitionnement basé sur les plages, mais au lieu de déterminer dans quelle plage les données de la clé de fragment se trouvent, chaque clé est liée à son propre fragment spécifique. Le partitionnement basé sur un annuaire est un bon choix par rapport au partitionnement basé sur les plages dans les cas où la clé de fragment a une faible cardinalité — c’est-à-dire, qu’elle a un faible nombre de valeurs possibles — et qu’il n’est pas pertinent qu’un fragment stocke une plage de clés. Notez qu’il se distingue également du partitionnement basé sur les clés en ce qu’il ne traite pas la clé de fragment à l’aide d’une fonction de hachage ; il vérifie simplement la clé dans une table de correspondance pour voir où les données doivent être écrites.

L'attrait principal du sharding basé sur un annuaire est sa flexibilité. Les architectures de sharding basées sur des plages vous limitent à spécifier des plages de valeurs, tandis que celles basées sur des clés vous limitent à utiliser une fonction de hachage fixe qui, comme mentionné précédemment, peut être extrêmement difficile à changer plus tard. Le sharding basé sur un annuaire, en revanche, vous permet d'utiliser n'importe quel système ou algorithme pour attribuer des entrées de données aux fragments, et il est relativement facile d'ajouter dynamiquement des fragments en utilisant cette approche.

Bien que le sharding basé sur un répertoire soit la méthode de sharding la plus flexible parmi celles discutées ici, le besoin de se connecter à la table de consultation avant chaque requête ou écriture peut avoir un impact préjudiciable sur les performances d'une application. De plus, la table de consultation peut devenir un point de défaillance unique : si elle devient corrompue ou échoue d'une autre manière, cela peut affecter la capacité à écrire de nouvelles données ou à accéder aux données existantes.

Dois-je me fragmenter ?

Que l'on doive ou non mettre en œuvre une architecture de base de données fragmentée est presque toujours un sujet de débat. Certains considèrent le sharding comme une conséquence inévitable pour les bases de données atteignant une certaine taille, tandis que d'autres le voient comme un casse-tête à éviter sauf si c'est absolument nécessaire, en raison de la complexité opérationnelle que le sharding ajoute.

En raison de cette complexité supplémentaire, le sharding n'est généralement effectué que lorsqu'on traite de très grandes quantités de données. Voici quelques scénarios courants où il peut être avantageux de sharder une base de données :

  • La quantité de données d'application augmente jusqu'à dépasser la capacité de stockage d'un seul nœud de base de données.
  • Le volume d'écritures ou de lectures sur la base de données dépasse ce qu'un seul nœud ou ses répliques en lecture peuvent gérer, entraînant des temps de réponse ralentis ou des expirations de délai.
  • La bande passante réseau requise par l'application dépasse la bande passante disponible pour un seul nœud de base de données et toutes les répliques en lecture, ce qui entraîne des temps de réponse ralentis ou des délais d'attente.

Avant de procéder au sharding, vous devriez épuiser toutes les autres options pour optimiser votre base de données. Parmi les optimisations que vous pourriez envisager, on peut inclure :

  • Configuration d'une base de données distante. Si vous travaillez avec une application monolithique dans laquelle tous ses composants résident sur le même serveur, vous pouvez améliorer les performances de votre base de données en la transférant sur sa propre machine. Cela n'ajoute pas autant de complexité que le sharding puisque les tables de la base de données restent intactes. Cependant, cela vous permet toujours de faire évoluer verticalement votre base de données indépendamment du reste de votre infrastructure.
  • Mise en œuvre de la mise en cache. Si les performances en lecture de votre application posent problème, la mise en cache est une stratégie qui peut aider à les améliorer. La mise en cache consiste à stocker temporairement en mémoire des données qui ont déjà été demandées, ce qui vous permet d’y accéder beaucoup plus rapidement par la suite.
  • Créer une ou plusieurs répliques en lecture. Une autre stratégie qui peut aider à améliorer les performances de lecture consiste à copier les données d'un serveur de base de données (le serveur principal) vers un ou plusieurs serveurs secondaires. Ensuite, chaque nouvelle écriture se fait sur le serveur principal avant d'être copiée vers les secondaires, tandis que les lectures sont effectuées exclusivement sur les serveurs secondaires. Répartir les lectures et les écritures de cette manière empêche qu'une seule machine prenne trop de charge, ce qui contribue à éviter les ralentissements et les plantages. Notez que la création de répliques en lecture nécessite plus de ressources informatiques et coûte donc plus d'argent, ce qui peut représenter une contrainte importante pour certains.
  • Mise à niveau vers un serveur plus grand. Dans la plupart des cas, faire évoluer son serveur de base de données vers une machine avec plus de ressources nécessite moins d’efforts que le sharding. Comme pour la création de répliques de lecture, un serveur amélioré avec plus de ressources coûtera probablement plus cher. Par conséquent, vous ne devriez procéder au redimensionnement que si cela s’avère réellement être votre meilleure option.

Gardez à l'esprit que si votre application ou site web dépasse un certain point, aucune de ces stratégies ne suffira à améliorer les performances à elle seule. Dans de tels cas, le partitionnement pourrait en effet être la meilleure option pour vous.

Conclusion

Le sharding peut être une excellente solution pour ceux qui cherchent à faire évoluer leur base de données horizontalement. Cependant, il ajoute également beaucoup de complexité et crée davantage de points de défaillance potentiels pour votre application. Le sharding peut être nécessaire pour certains, mais le temps et les ressources nécessaires pour créer et maintenir une architecture shardée pourraient l'emporter sur les avantages pour d'autres.

En lisant cet article conceptuel, vous devriez avoir une compréhension plus claire des avantages et des inconvénients du sharding. À l'avenir, vous pourrez utiliser ces connaissances pour prendre une décision plus éclairée sur le fait de savoir si une architecture de base de données sharded convient ou non à votre application.