RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters

La tolérance aux pannes et la haute disponibilité sont des sujets importants, nous consacrerons donc des articles séparés à RabbitMQ et Kafka. Cet article concerne RabbitMQ et le suivant concerne Kafka, en comparaison avec RabbitMQ. C’est un long article, alors installez-vous confortablement.

Examinons les stratégies de tolérance aux pannes, de cohérence et de haute disponibilité (HA), ainsi que les compromis que fait chaque stratégie. RabbitMQ peut s'exécuter sur un cluster de nœuds et est ensuite classé comme système distribué. Lorsqu'il s'agit de systèmes distribués, on parle souvent de cohérence et de disponibilité.

Ces concepts décrivent le comportement d'un système en cas de panne. Échec de la connexion réseau, panne du serveur, panne du disque dur, indisponibilité temporaire du serveur en raison d'un garbage collection, d'une perte de paquets ou d'un ralentissement de la connexion réseau. Tout cela peut entraîner des pertes de données ou des conflits. Il s'avère qu'il est pratiquement impossible de mettre en place un système qui soit à la fois totalement cohérent (pas de perte de données, pas de divergence de données) et disponible (acceptera les lectures et les écritures) pour tous les scénarios de panne.

Nous verrons que la cohérence et la disponibilité se situent aux extrémités opposées du spectre, et vous devez choisir la manière d'optimiser. La bonne nouvelle est qu’avec RabbitMQ ce choix est possible. Vous disposez de ce genre de leviers « ringards » pour faire pencher la balance vers une plus grande cohérence ou une plus grande accessibilité.

Nous accorderons une attention particulière aux configurations entraînant une perte de données en raison d'enregistrements confirmés. Il existe une chaîne de responsabilité entre les éditeurs, les courtiers et les consommateurs. Une fois le message transmis au courtier, c'est à lui de ne pas perdre le message. Lorsque le courtier accuse réception du message par l'éditeur, nous ne nous attendons pas à ce qu'il soit perdu. Mais nous verrons que cela peut réellement se produire en fonction de la configuration de votre courtier et de votre éditeur.

Primitives de résilience à nœud unique

File d'attente/routage résilient

Il existe deux types de files d'attente dans RabbitMQ : durables et non durables. Toutes les files d'attente sont enregistrées dans la base de données Mnesia. Les files d'attente durables sont réannoncées au démarrage du nœud et survivent ainsi aux redémarrages, aux pannes du système ou aux pannes du serveur (tant que les données sont conservées). Cela signifie que tant que vous déclarez le routage (échange) et la file d’attente résilients, l’infrastructure de file d’attente/routage reviendra en ligne.

Les files d'attente volatiles et le routage sont supprimés au redémarrage du nœud.

Messages persistants

Ce n’est pas parce qu’une file d’attente est durable que tous ses messages survivront au redémarrage d’un nœud. Seuls les messages définis par l'éditeur comme durable (persistant). Les messages persistants créent une charge supplémentaire sur le courtier, mais si la perte de message est inacceptable, il n'y a pas d'autre option.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 1. Matrice de durabilité

Clustering avec mise en miroir de files d'attente

Pour survivre à la perte d’un courtier, nous avons besoin de licenciements. Nous pouvons combiner plusieurs nœuds RabbitMQ dans un cluster, puis ajouter une redondance supplémentaire en répliquant les files d'attente entre plusieurs nœuds. De cette façon, si un nœud tombe en panne, nous ne perdons pas de données et restons disponibles.

Mise en miroir des files d'attente :

  • une file d'attente principale (maître), qui reçoit toutes les commandes d'écriture et de lecture
  • un ou plusieurs miroirs qui reçoivent tous les messages et métadonnées de la file d'attente principale. Ces miroirs ne sont pas là pour la mise à l'échelle, mais uniquement pour la redondance.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 2. Mise en miroir des files d'attente

La mise en miroir est définie par la stratégie appropriée. Vous pouvez y sélectionner le coefficient de réplication et même les nœuds sur lesquels la file d'attente doit être située. Exemples:

  • ha-mode: all
  • ha-mode: exactly, ha-params: 2 (un maître et un miroir)
  • ha-mode: nodes, ha-params: rabbit@node1, rabbit@node2

Confirmation de l'éditeur

Pour obtenir un enregistrement cohérent, des confirmations de l'éditeur sont requises. Sans eux, les messages risquent d'être perdus. Une confirmation est envoyée à l'éditeur une fois le message écrit sur le disque. RabbitMQ écrit les messages sur le disque non pas à leur réception, mais sur une base périodique, de l'ordre de plusieurs centaines de millisecondes. Lorsqu'une file d'attente est mise en miroir, un accusé de réception est envoyé uniquement une fois que tous les miroirs ont également écrit leur copie du message sur le disque. Cela signifie que l’utilisation des confirmations ajoute de la latence, mais si la sécurité des données est importante, alors elles sont nécessaires.

File d'attente de basculement

Lorsqu'un courtier se ferme ou plante, tous les chefs de file d'attente (maîtres) de ce nœud se bloquent en même temps. Le cluster sélectionne ensuite le miroir le plus ancien de chaque maître et le promeut comme nouveau maître.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 3. Plusieurs files d'attente en miroir et leurs politiques

Le courtier 3 tombe en panne. Notez que le miroir de la file d'attente C sur le courtier 2 est promu au rang de maître. Notez également qu'un nouveau miroir a été créé pour la file d'attente C sur le courtier 1. RabbitMQ tente toujours de maintenir le facteur de réplication spécifié dans vos stratégies.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 4. Le courtier 3 échoue, entraînant l'échec de la file d'attente C

Le prochain Broker 1 tombe ! Il ne nous reste qu'un seul courtier. Le miroir de la file d'attente B est promu maître.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Fig. 5

Nous avons renvoyé le courtier 1. Quelle que soit la capacité des données à survivre à la perte et à la récupération du courtier, tous les messages de la file d'attente en miroir sont supprimés au redémarrage. C’est important à noter car il y aura des conséquences. Nous examinerons ces implications sous peu. Le courtier 1 est donc à nouveau membre du cluster, et le cluster tente de se conformer aux politiques et crée donc des miroirs sur le courtier 1.

Dans ce cas, la perte du courtier 1 était totale, tout comme les données, de sorte que la file d'attente B non mise en miroir était complètement perdue.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 6. Le courtier 1 reprend du service

Le courtier 3 est de nouveau en ligne, donc les files d'attente A et B récupèrent les miroirs créés dessus pour satisfaire leurs politiques HA. Mais maintenant, toutes les files d’attente principales sont sur un seul nœud ! Ce n'est pas idéal, une répartition uniforme entre les nœuds est préférable. Malheureusement, il n'y a pas beaucoup d'options ici pour rééquilibrer les masters. Nous reviendrons sur ce problème plus tard car nous devons d'abord examiner la synchronisation des files d'attente.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 7. Le courtier 3 reprend du service. Toutes les files d'attente principales sur un seul nœud !

Alors maintenant, vous devriez avoir une idée de la façon dont les miroirs assurent la redondance et la tolérance aux pannes. Cela garantit la disponibilité en cas de panne d'un seul nœud et protège contre la perte de données. Mais nous n’avons pas encore fini, car en réalité c’est beaucoup plus compliqué.

Синхронизация

Lors de la création d'un nouveau miroir, tous les nouveaux messages seront toujours répliqués sur ce miroir et sur tous les autres. Quant aux données existantes dans la file d'attente principale, nous pouvons les répliquer vers un nouveau miroir, qui devient une copie complète du maître. Nous pouvons également choisir de ne pas répliquer les messages existants et de laisser la file d'attente principale et le nouveau miroir converger dans le temps, les nouveaux messages arrivant en queue et les messages existants sortant en tête de la file d'attente principale.

Cette synchronisation est effectuée automatiquement ou manuellement et est gérée à l'aide d'une politique de file d'attente. Regardons un exemple.

Nous avons deux files d'attente en miroir. La file d'attente A est synchronisée automatiquement et la file d'attente B est synchronisée manuellement. Les deux files d'attente contiennent dix messages.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 8. Deux files d'attente avec des modes de synchronisation différents

Nous perdons maintenant le courtier 3.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 9. Le courtier 3 est tombé

Le courtier 3 reprend du service. Le cluster crée un miroir pour chaque file d'attente sur le nouveau nœud et synchronise automatiquement la nouvelle file d'attente A avec le maître. Cependant, le miroir de la nouvelle Queue B reste vide. De cette façon, nous avons une redondance complète sur la file d'attente A et un seul miroir pour les messages existants de la file d'attente B.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 10. Le nouveau miroir de la file d'attente A reçoit tous les messages existants, mais pas le nouveau miroir de la file d'attente B.

Dix autres messages arrivent dans les deux files d'attente. Le courtier 2 plante alors et la file d'attente A revient au miroir le plus ancien, qui se trouve sur le courtier 1. Il n'y a aucune perte de données en cas de panne. Dans la file d'attente B, il y a vingt messages dans le maître et seulement dix dans le miroir car cette file d'attente n'a jamais répliqué les dix messages d'origine.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 11. La file d'attente A revient au courtier 1 sans perdre de messages

Dix autres messages arrivent dans les deux files d'attente. Maintenant, le courtier 1 plante. La file d'attente A passe facilement au miroir sans perdre de messages. Cependant, la file d'attente B rencontre des problèmes. À ce stade, nous pouvons optimiser soit la disponibilité, soit la cohérence.

Si nous voulons optimiser l'accessibilité, alors la politique ha-promotion-en-échec devrait être installé dans toujours. Il s'agit de la valeur par défaut, vous ne pouvez donc tout simplement pas spécifier de stratégie du tout. Dans ce cas, nous autorisons essentiellement les pannes dans les miroirs non synchronisés. Cela entraînera la perte des messages, mais la file d'attente restera lisible et inscriptible.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 12. La file d'attente A est ramenée au courtier 3 sans perdre de messages. La file d'attente B revient au courtier 3 avec dix messages perdus

Nous pouvons également installer ha-promote-on-failure dans le sens when-synced. Dans ce cas, au lieu de revenir au miroir, la file d'attente attendra que le courtier 1 avec ses données revienne en mode en ligne. Après son retour, la file d'attente principale est de retour sur le courtier 1 sans aucune perte de données. La disponibilité est sacrifiée au profit de la sécurité des données. Mais il s'agit d'un mode risqué qui peut même entraîner une perte totale de données, que nous examinerons sous peu.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 13. La file d'attente B reste indisponible après la perte du courtier 1

Vous vous demandez peut-être : « Vaut-il mieux ne jamais utiliser la synchronisation automatique ? » La réponse est que la synchronisation est une opération bloquante. Pendant la synchronisation, la file d'attente principale ne peut effectuer aucune opération de lecture ou d'écriture !

Regardons un exemple. Nous avons désormais de très longues files d'attente. Comment peuvent-ils atteindre une telle taille ? Pour plusieurs raisons :

  • Les files d'attente ne sont pas activement utilisées
  • Ce sont des files d'attente à grande vitesse et, à l'heure actuelle, les consommateurs sont lents
  • Ce sont des files d'attente à grande vitesse, il y a eu un problème et les consommateurs rattrapent leur retard

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 14. Deux grandes files d'attente avec des modes de synchronisation différents

Maintenant, le courtier 3 tombe.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 15. Le courtier 3 tombe, laissant un maître et un miroir dans chaque file d'attente

Broker 3 revient en ligne et de nouveaux miroirs sont créés. La file d'attente principale A commence à répliquer les messages existants vers le nouveau miroir et pendant ce temps, la file d'attente est indisponible. Il faut deux heures pour répliquer les données, ce qui entraîne deux heures d'indisponibilité pour cette file d'attente !

Cependant, la file d'attente B reste disponible pendant toute la période. Elle a sacrifié une certaine redondance pour l'accessibilité.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 16. La file d'attente reste indisponible pendant la synchronisation

Après deux heures, la file d'attente A devient également disponible et peut recommencer à accepter des lectures et des écritures.

Mises à jour

Ce comportement bloquant lors de la synchronisation rend difficile la mise à jour des clusters avec des files d'attente très volumineuses. À un moment donné, le nœud maître doit être redémarré, ce qui signifie soit passer à un miroir, soit désactiver la file d'attente pendant la mise à niveau du serveur. Si nous choisissons de faire la transition, nous perdrons des messages si les miroirs ne sont pas synchronisés. Par défaut, lors d'une panne de courtier, aucun basculement vers un miroir non synchronisé n'est effectué. Cela signifie que dès le retour du courtier, nous ne perdons aucun message, le seul dommage était une simple file d'attente. Les règles de comportement lorsqu'un courtier est déconnecté sont définies par la politique ha-promote-on-shutdown. Vous pouvez définir l'une des deux valeurs suivantes :

  • always= la transition vers les miroirs non synchronisés est activée
  • when-synced= transition vers un miroir synchronisé uniquement, sinon la file d'attente devient illisible et illisible. La file d'attente reprend du service dès le retour du courtier

D'une manière ou d'une autre, avec de grandes files d'attente, vous devez choisir entre la perte de données et l'indisponibilité.

Quand la disponibilité améliore la sécurité des données

Il y a une autre complication à considérer avant de prendre une décision. Même si la synchronisation automatique est préférable pour la redondance, quel est son impact sur la sécurité des données ? Bien sûr, avec une meilleure redondance, RabbitMQ est moins susceptible de perdre les messages existants, mais qu'en est-il des nouveaux messages des éditeurs ?

Ici, vous devez considérer les éléments suivants :

  • L'éditeur pourrait-il simplement renvoyer une erreur et demander au service ou à l'utilisateur en amont de réessayer plus tard ?
  • L'éditeur peut-il enregistrer le message localement ou dans une base de données pour réessayer plus tard ?

Si l’éditeur peut uniquement supprimer le message, alors en fait, améliorer l’accessibilité améliore également la sécurité des données.

Il faut donc rechercher un équilibre et la solution dépend de la situation spécifique.

Problèmes avec ha-promote-on-failure=when-synced

Idée ha-promotion-en-échec= lors de la synchronisation est que nous empêchons de passer à un miroir non synchronisé et évitons ainsi la perte de données. La file d'attente reste illisible ou inscriptible. Au lieu de cela, nous essayons de récupérer le courtier en panne avec ses données intactes afin qu'il puisse reprendre son fonctionnement en tant que maître sans perte de données.

Mais (et c'est un gros mais) si le courtier a perdu ses données, alors nous avons un gros problème : la file d'attente est perdue ! Toutes les données ont disparu ! Même si vous avez des miroirs qui rattrapent en grande partie la file d'attente principale, ces miroirs sont également supprimés.

Pour rajouter un nœud du même nom, on dit au cluster d'oublier le nœud perdu (avec la commande lapinmqctl oublier_cluster_node) et démarrez un nouveau courtier avec le même nom d'hôte. Tandis que le cluster se souvient du nœud perdu, il se souvient de l'ancienne file d'attente et des miroirs non synchronisés. Lorsqu'il est demandé à un cluster d'oublier un nœud orphelin, cette file d'attente est également oubliée. Nous devons maintenant le déclarer à nouveau. Nous avons perdu toutes les données, même si nous avions des miroirs avec un ensemble partiel de données. Il vaudrait mieux passer à un miroir non synchronisé !

Par conséquent, la synchronisation manuelle (et l'échec de la synchronisation) en combinaison avec ha-promote-on-failure=when-synced, à mon avis, assez risqué. La documentation indique que cette option existe pour la sécurité des données, mais c'est un couteau à double tranchant.

Rééquilibrage principal

Comme promis, revenons au problème du cumul de tous les maîtres sur un ou plusieurs nœuds. Cela peut même se produire à la suite d’une mise à jour progressive du cluster. Dans un cluster à trois nœuds, toutes les files d'attente principales s'accumuleront sur un ou deux nœuds.

Le rééquilibrage des maîtres peut être problématique pour deux raisons :

  • Il n’existe pas de bons outils pour effectuer un rééquilibrage
  • Synchronisation des files d'attente

Il existe un tiers pour le rééquilibrage Plugin, qui n'est pas officiellement pris en charge. Concernant les plugins tiers dans le manuel RabbitMQ c'est dit: « Le plugin fournit des outils de configuration et de reporting supplémentaires, mais n'est ni pris en charge ni vérifié par l'équipe RabbitMQ. À utiliser à vos risques et périls."

Il existe une autre astuce pour déplacer la file d'attente principale via les stratégies HA. Le manuel mentionne scénario pour ça. Cela fonctionne comme ceci :

  • Supprime tous les miroirs à l’aide d’une stratégie temporaire ayant une priorité plus élevée que la stratégie HA existante.
  • Modifie la stratégie temporaire HA pour utiliser le mode nœud, en spécifiant le nœud vers lequel la file d'attente principale doit être transférée.
  • Synchronise la file d'attente pour la migration push.
  • Une fois la migration terminée, supprime la stratégie temporaire. La stratégie HA initiale prend effet et le nombre requis de miroirs est créé.

L’inconvénient est que cette approche peut ne pas fonctionner si vous avez de grandes files d’attente ou des exigences strictes en matière de redondance.

Voyons maintenant comment les clusters RabbitMQ fonctionnent avec les partitions réseau.

Perte de connectivité

Les nœuds d'un système distribué sont connectés par des liaisons réseau, et les liaisons réseau peuvent et seront déconnectées. La fréquence des pannes dépend de l'infrastructure locale ou de la fiabilité du cloud sélectionné. Dans tous les cas, les systèmes distribués doivent être capables d’y faire face. Une fois de plus, nous avons le choix entre disponibilité et cohérence, et encore une fois, la bonne nouvelle est que RabbitMQ propose les deux options (mais pas en même temps).

Avec RabbitMQ, nous avons deux options principales :

  • Autoriser la division logique (cerveau divisé). Cela garantit la disponibilité, mais peut entraîner une perte de données.
  • Désactivez la séparation logique. Peut entraîner une perte de disponibilité à court terme en fonction de la manière dont les clients se connectent au cluster. Peut également conduire à une indisponibilité totale dans un cluster à deux nœuds.

Mais qu’est-ce que la séparation logique ? C'est à ce moment qu'un cluster se divise en deux en raison d'une perte de connexion réseau. De chaque côté, les miroirs sont promus au rang de maître, de sorte qu'il y a éventuellement plusieurs maîtres par file d'attente.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 17. File d'attente principale et deux miroirs, chacun sur un nœud distinct. Ensuite, une panne de réseau se produit et un miroir se détache. Le nœud séparé voit que les deux autres sont tombés et présente ses miroirs au maître. Nous avons maintenant deux files d'attente principales, à la fois inscriptibles et lisibles.

Si les éditeurs envoient des données aux deux maîtres, nous nous retrouvons avec deux copies divergentes de la file d'attente.

Les différents modes de RabbitMQ offrent soit la disponibilité, soit la cohérence.

Mode Ignorer (par défaut)

Ce mode garantit l'accessibilité. Après la perte de connectivité, une séparation logique se produit. Une fois la connectivité restaurée, l'administrateur doit décider à quelle partition donner la priorité. Le côté perdant sera redémarré et toutes les données accumulées de ce côté seront perdues.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 18. Trois éditeurs sont associés à trois courtiers. En interne, le cluster achemine toutes les requêtes vers la file d'attente principale sur Broker 2.

Nous perdons maintenant le courtier 3. Il voit que d'autres courtiers ont chuté et promeut son miroir au rang de maître. C'est ainsi qu'une séparation logique se produit.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 19. Division logique (cerveau divisé). Les enregistrements sont répartis dans deux files d'attente principales et les deux copies divergent.

La connectivité est rétablie, mais la séparation logique demeure. L'administrateur doit sélectionner manuellement le camp perdant. Dans le cas ci-dessous, l'administrateur redémarre le Broker 3. Tous les messages qu'il n'a pas réussi à transmettre sont perdus.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 20. L'administrateur désactive Broker 3.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 21. L'administrateur démarre Broker 3 et celui-ci rejoint le cluster, perdant ainsi tous les messages qui y étaient laissés.

Lors de la perte de connectivité et après sa restauration, le cluster et cette file d'attente étaient disponibles en lecture et en écriture.

Mode de réparation automatique

Fonctionne de manière similaire au mode Ignorer, sauf que le cluster lui-même choisit automatiquement le côté perdant après la division et la restauration de la connectivité. Le côté perdant retourne vide dans le cluster et la file d'attente perd tous les messages envoyés uniquement à ce côté.

Suspendre le mode minoritaire

Si nous ne voulons pas autoriser le partitionnement logique, notre seule option consiste à ignorer les lectures et les écritures du côté le plus petit après la partition du cluster. Lorsque le courtier constate qu'il est plutôt petit, il suspend son travail, c'est-à-dire qu'il ferme toutes les connexions existantes et en refuse de nouvelles. Une fois par seconde, il vérifie la restauration de la connectivité. Une fois la connectivité restaurée, il reprend son fonctionnement et rejoint le cluster.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 22. Trois éditeurs sont associés à trois courtiers. En interne, le cluster achemine toutes les requêtes vers la file d'attente principale sur Broker 2.

Les courtiers 1 et 2 se séparent ensuite du courtier 3. Au lieu de promouvoir leur miroir au rang de maître, le courtier 3 se suspend et devient indisponible.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 23. Le courtier 3 fait une pause, déconnecte tous les clients et rejette les demandes de connexion.

Une fois la connectivité restaurée, elle revient au cluster.

Regardons un autre exemple où la file d'attente principale se trouve sur Broker 3.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 24. File d'attente principale sur le courtier 3.

La même perte de connectivité se produit alors. Le courtier 3 fait une pause car il est plus petit. De l'autre côté, les nœuds voient que le courtier 3 est tombé, donc l'ancien miroir des courtiers 1 et 2 est promu maître.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 25. Transition vers le courtier 2 si le courtier 3 n'est pas disponible.

Une fois la connectivité restaurée, Broker 3 rejoindra le cluster.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité dans les clusters
Riz. 26. Le cluster est revenu à un fonctionnement normal.

La chose importante à comprendre ici est que nous obtenons de la cohérence, mais nous pouvons également obtenir de la disponibilité, si Nous transférerons avec succès les clients vers la majeure partie de la section. Pour la plupart des situations, je choisirais personnellement le mode Pause Minorité, mais cela dépend vraiment de chaque cas individuel.

Pour garantir la disponibilité, il est important de s'assurer que les clients se connectent correctement à l'hôte. Examinons nos options.

Assurer la connectivité client

Nous disposons de plusieurs options pour diriger les clients vers la partie principale du cluster ou vers des nœuds de travail (après la panne d'un nœud) après une perte de connectivité. Rappelons d'abord qu'une file d'attente spécifique est hébergée sur un nœud spécifique, mais que le routage et les politiques sont répliqués sur tous les nœuds. Les clients peuvent se connecter à n’importe quel nœud et le routage interne les dirigera là où ils doivent aller. Mais lorsqu'un nœud est suspendu, il rejette les connexions, les clients doivent donc se connecter à un autre nœud. Si le nœud tombe, il ne peut pas faire grand-chose.

Nos options :

  • Le cluster est accessible à l'aide d'un équilibreur de charge qui parcourt simplement les nœuds et les clients réessayent de se connecter jusqu'à ce qu'ils réussissent. Si un nœud est en panne ou suspendu, les tentatives de connexion à ce nœud échoueront, mais les tentatives ultérieures seront dirigées vers d'autres serveurs (de manière alternée). Cela convient à une perte de connectivité à court terme ou à un serveur en panne qui sera rapidement rétabli.
  • Accédez au cluster via un équilibreur de charge et supprimez les nœuds suspendus/en échec de la liste dès qu'ils sont détectés. Si nous le faisons rapidement et si les clients peuvent réessayer de se connecter, nous obtiendrons une disponibilité constante.
  • Donnez à chaque client une liste de tous les nœuds, et le client en sélectionne un au hasard lors de la connexion. S'il reçoit une erreur lors de la tentative de connexion, il passe au nœud suivant dans la liste jusqu'à ce qu'il se connecte.
  • Supprimez le trafic d'un nœud défaillant/suspendu à l'aide du DNS. Cela se fait en utilisant un petit TTL.

résultats

Le clustering RabbitMQ a ses avantages et ses inconvénients. Les inconvénients les plus sérieux sont les suivants :

  • lorsqu'ils rejoignent un cluster, les nœuds suppriment leurs données ;
  • le blocage de la synchronisation entraîne l'indisponibilité de la file d'attente.

Toutes les décisions difficiles découlent de ces deux caractéristiques architecturales. Si RabbitMQ pouvait enregistrer les données lorsque le cluster est rejoint, la synchronisation serait alors plus rapide. S'il était capable d'effectuer une synchronisation non bloquante, il prendrait mieux en charge les grandes files d'attente. La résolution de ces deux problèmes améliorerait considérablement les performances de RabbitMQ en tant que technologie de messagerie tolérante aux pannes et hautement disponible. J'hésiterais à recommander RabbitMQ avec clustering dans les situations suivantes :

  • Réseau peu fiable.
  • Stockage peu fiable.
  • Très longues files d'attente.

En ce qui concerne les paramètres de haute disponibilité, tenez compte des éléments suivants :

  • ha-promote-on-failure=always
  • ha-sync-mode=manual
  • cluster_partition_handling=ignore (ou autoheal)
  • messages persistants
  • garantir que les clients se connectent au nœud actif en cas de panne d'un nœud

Pour des raisons de cohérence (sécurité des données), tenez compte des paramètres suivants :

  • Confirmations de l'éditeur et accusés de réception manuels du côté du consommateur
  • ha-promote-on-failure=when-synced, si les éditeurs peuvent réessayer plus tard et si vous disposez d'un stockage très fiable ! Sinon mettre =always.
  • ha-sync-mode=automatic (mais pour les grandes files d'attente inactives, le mode manuel peut être requis ; déterminez également si l'indisponibilité entraînera la perte de messages)
  • Suspendre le mode minoritaire
  • messages persistants

Nous n'avons pas encore abordé toutes les questions de tolérance aux pannes et de haute disponibilité ; par exemple, comment effectuer en toute sécurité des procédures administratives (telles que des mises à jour progressives). Il faut aussi parler de fédération et du plugin Shovel.

Si j'ai raté autre chose, faites-le-moi savoir.

Voir aussi mon poster, où j'effectue des ravages sur un cluster RabbitMQ à l'aide de Docker et Blockade pour tester certains des scénarios de perte de messages décrits dans cet article.

Articles précédents de la série:
N° 1 - habr.com/ru/company/itsumma/blog/416629
N° 2 - habr.com/ru/company/itsumma/blog/418389
N° 3 - habr.com/ru/company/itsumma/blog/437446

Source: habr.com

Ajouter un commentaire