Pourquoi pourriez-vous avoir besoin d'une réplication semi-synchrone ?

Salut tout le monde. Vladislav Rodin est en contact. J'enseigne actuellement des cours sur l'architecture logicielle et l'architecture logicielle à haute contrainte à l'OTUS. En prévision du début d'un nouveau flux de cours "Architecte à charge élevée" J'ai décidé d'écrire un court morceau de matériel original que je souhaite partager avec vous.

Pourquoi pourriez-vous avoir besoin d'une réplication semi-synchrone ?

introduction

Étant donné que le disque dur ne peut effectuer qu'environ 400 à 700 opérations par seconde (ce qui est incomparable avec les rps typiques pour un système à forte charge), la base de données de disque classique constitue le goulot d'étranglement de l'architecture. Il est donc nécessaire d’accorder une attention particulière aux modèles de mise à l’échelle de ce stockage.

Actuellement, il existe 2 modèles de mise à l'échelle des bases de données : la réplication et le partitionnement. Le partage vous permet de faire évoluer l'opération d'écriture et, par conséquent, de réduire le nombre de rps par écriture et par serveur dans votre cluster. La réplication permet de faire la même chose, mais avec des opérations de lecture. C'est à ce modèle que cet article est consacré.

réplication

Si vous regardez la réplication à un niveau très élevé, c'est une chose simple : vous aviez un serveur, il y avait des données dessus, et puis ce serveur ne pouvait plus faire face à la charge de lecture de ces données. Vous ajoutez quelques serveurs supplémentaires, synchronisez les données sur tous les serveurs et l'utilisateur peut lire à partir de n'importe quel serveur de votre cluster.

Malgré son apparente simplicité, il existe plusieurs options pour classer les différentes implémentations de ce schéma :

  • Par rôles dans le cluster (maître-maître ou maître-esclave)
  • Par objets envoyés (basés sur des lignes, basés sur des instructions ou mixtes)
  • Selon le mécanisme de synchronisation des nœuds

Aujourd'hui, nous traiterons du point 3.

Comment se déroule une validation de transaction ?

Ce sujet n'est pas directement lié à la réplication ; un article séparé peut être écrit à ce sujet, mais comme une lecture plus approfondie est inutile sans comprendre le mécanisme de validation des transactions, permettez-moi de vous rappeler les choses les plus élémentaires. Une validation de transaction se déroule en 3 étapes :

  1. Enregistrer une transaction dans le journal de la base de données.
  2. Utiliser une transaction dans un moteur de base de données.
  3. Confirmation au client que la transaction a été appliquée avec succès.

Dans différentes bases de données, cet algorithme peut avoir des nuances : par exemple, dans le moteur InnoDB de la base de données MySQL, il y a 2 journaux : un pour la réplication (journal binaire) et l'autre pour maintenir l'ACID (journal d'annulation/redo), tandis que dans PostgreSQL il existe un journal qui remplit les deux fonctions (journal d'écriture anticipée = WAL). Mais ce qui est présenté ci-dessus est précisément le concept général qui permet de ne pas prendre en compte de telles nuances.

Réplication synchrone (sync)

Ajoutons une logique pour répliquer les modifications reçues à l'algorithme de validation de transaction :

  1. Enregistrer une transaction dans le journal de la base de données.
  2. Utiliser une transaction dans un moteur de base de données.
  3. Envoi de données à toutes les répliques.
  4. Recevoir la confirmation de toutes les répliques qu'une transaction a été effectuée sur elles.
  5. Confirmation au client que la transaction a été appliquée avec succès.

Avec cette approche, nous obtenons un certain nombre d'inconvénients :

  • le client attend que les modifications soient appliquées à toutes les répliques.
  • à mesure que le nombre de nœuds dans le cluster augmente, nous diminuons la probabilité que l'opération d'écriture réussisse.

Si tout est plus ou moins clair avec le 1er point, alors les raisons du 2ème point méritent d'être expliquées. Si lors de la réplication synchrone nous ne recevons pas de réponse d'au moins un nœud, nous annulons la transaction. Ainsi, en augmentant le nombre de nœuds dans le cluster, vous augmentez la probabilité qu'une opération d'écriture échoue.

Pouvons-nous attendre la confirmation d'un certain pourcentage de nœuds seulement, par exemple de 51 % (quorum) ? Oui, nous pouvons, mais dans la version classique, la confirmation de tous les nœuds est requise, car c'est ainsi que nous pouvons garantir une cohérence complète des données dans le cluster, ce qui constitue un avantage incontestable de ce type de réplication.

Réplication asynchrone (asynchrone)

Modifions l'algorithme précédent. Nous enverrons les données aux répliques « un peu plus tard », et « un peu plus tard » les modifications seront appliquées aux répliques :

  1. Enregistrer une transaction dans le journal de la base de données.
  2. Utiliser une transaction dans un moteur de base de données.
  3. Confirmation au client que la transaction a été appliquée avec succès.
  4. Envoi de données aux réplicas et application de modifications à celles-ci.

Cette approche conduit au fait que le cluster fonctionne rapidement, car nous ne faisons pas attendre le client que les données atteignent les réplicas et même soient validées.

Mais la condition de déversement des données sur des répliques « quelque temps plus tard » peut conduire à la perte d'une transaction, et à la perte d'une transaction confirmée par l'utilisateur, car si les données n'ont pas eu le temps d'être répliquées, une confirmation au client le succès de l'opération a été envoyé et le nœud sur lequel les modifications sont arrivées a planté le disque dur, nous perdons la transaction, ce qui peut entraîner des conséquences très désagréables.

Réplication semi-synchronisée

Enfin, nous arrivons à la réplication semi-synchrone. Ce type de réplication est peu connu ni très courant, mais il présente un intérêt considérable car il permet de combiner les avantages de la réplication synchrone et asynchrone.

Essayons de combiner les 2 approches précédentes. Nous ne garderons pas le client longtemps, mais nous exigerons que les données soient répliquées :

  1. Enregistrer une transaction dans le journal de la base de données.
  2. Utiliser une transaction dans un moteur de base de données.
  3. Envoi de données aux réplicas.
  4. Recevoir la confirmation de la réplique que les modifications ont été reçues (elles seront appliquées « quelque temps plus tard »).
  5. Confirmation au client que la transaction a été appliquée avec succès.

Veuillez noter qu'avec cet algorithme, la perte de transaction se produit uniquement si le nœud recevant les modifications et le nœud réplica échouent. La probabilité d’une telle défaillance est considérée comme faible et ces risques sont acceptés.

Mais avec cette approche, il existe un risque possible de lectures fantômes. Imaginons le scénario suivant : à l'étape 4, nous n'avons reçu de confirmation d'aucune réplique. Nous devons annuler cette transaction et ne pas renvoyer de confirmation au client. Étant donné que les données ont été appliquées à l'étape 2, il existe un intervalle de temps entre la fin de l'étape 2 et l'annulation de la transaction, pendant lequel les transactions parallèles peuvent voir des modifications qui ne devraient pas figurer dans la base de données.

Réplication semi-synchronisée sans perte

Si vous réfléchissez un peu, vous pouvez simplement inverser les étapes de l'algorithme et résoudre le problème des lectures fantômes dans ce scénario :

  1. Enregistrer une transaction dans le journal de la base de données.
  2. Envoi de données de réplique.
  3. Recevoir la confirmation de la réplique que les modifications ont été reçues (elles seront appliquées « quelque temps plus tard »).
  4. Utiliser une transaction dans un moteur de base de données.
  5. Confirmation au client que la transaction a été appliquée avec succès.

Désormais, nous validons les modifications uniquement si elles ont été répliquées.

conclusion

Comme toujours, il n’existe pas de solutions idéales ; il existe un ensemble de solutions, chacune ayant ses propres avantages et inconvénients et étant adaptée à la résolution de différentes classes de problèmes. Cela est absolument vrai pour le choix d'un mécanisme de synchronisation des données dans une base de données répliquée. L'ensemble des avantages de la réplication semi-synchrone est suffisamment solide et intéressant pour pouvoir être considéré comme digne d'attention, malgré sa faible prévalence.

C'est tout. Je te vois à cours!

Source: habr.com

Ajouter un commentaire