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

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

В dernier article nous avons examiné le clustering RabbitMQ pour la tolérance aux pannes et la haute disponibilité. Examinons maintenant en profondeur Apache Kafka.

Ici l'unité de réplication est la partition. Chaque sujet comporte une ou plusieurs sections. Chaque section a un leader avec ou sans adeptes. Lors de la création d'un sujet, vous précisez le nombre de partitions et le coefficient de réplication. La valeur habituelle est 3, ce qui signifie trois répliques : un leader et deux suiveurs.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 1. Quatre sections sont réparties entre trois courtiers

Toutes les demandes de lecture et d'écriture sont adressées au leader. Les abonnés envoient périodiquement des demandes au leader pour recevoir les derniers messages. Les consommateurs ne se tournent jamais vers les suiveurs ; ces derniers n’existent que pour la redondance et la tolérance aux pannes.

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

Échec de partition

Lorsqu’un courtier échoue, les dirigeants de plusieurs sections échouent souvent. Dans chacun d’eux, un suiveur d’un autre nœud devient le leader. En fait, ce n'est pas toujours le cas, puisque le facteur de synchronisation influence également : s'il y a des abonnés synchronisés, et sinon, si le passage à une réplique non synchronisée est autorisé. Mais ne compliquons pas les choses pour l'instant.

Le courtier 3 quitte le réseau et un nouveau leader est élu pour la section 2 chez le courtier 2.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 2. Le courtier 3 décède et son suiveur sur le courtier 2 est élu nouveau chef de la partition 2.

Puis le courtier 1 part et la section 1 perd également son chef, dont le rôle passe au courtier 2.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 3. Il reste un courtier. Tous les dirigeants sont sur un seul courtier sans redondance

Lorsque le courtier 1 revient en ligne, il ajoute quatre abonnés, offrant ainsi une certaine redondance à chaque partition. Mais tous les leaders sont restés sur le courtier 2.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 4. Les leaders restent sur le courtier 2

Lorsque le courtier 3 apparaît, nous revenons à trois répliques par partition. Mais tous les leaders sont toujours sur le courtier 2.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 5. Placement déséquilibré des leaders après la restauration des courtiers 1 et 3

Kafka dispose d'un outil pour un meilleur rééquilibrage des leaders que RabbitMQ. Là, vous deviez utiliser un plugin ou un script tiers qui modifiait les politiques de migration du nœud maître en réduisant la redondance pendant la migration. De plus, pour les files d'attente importantes, nous avons dû accepter une indisponibilité lors de la synchronisation.

Kafka a le concept de « répliques préférées » pour le rôle de leader. Lorsque des partitions de sujets sont créées, Kafka tente de répartir les leaders de manière égale entre les nœuds et marque ces premiers leaders comme préférés. Au fil du temps, en raison des redémarrages des serveurs, des pannes et des pannes de connectivité, les dirigeants peuvent se retrouver sur d'autres nœuds, comme dans le cas extrême décrit ci-dessus.

Pour résoudre ce problème, Kafka propose deux options :

  • Option auto.leader.rebalance.enable=true permet au nœud contrôleur de réaffecter automatiquement les leaders aux répliques préférées et de restaurer ainsi une distribution uniforme.
  • L'administrateur peut exécuter le script kafka-preferred-replica-election.sh pour une réaffectation manuelle.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 6. Répliques après rééquilibrage

Il s’agissait d’une version simplifiée de l’échec, mais la réalité est plus complexe, même s’il n’y a rien de trop compliqué ici. Tout se résume aux répliques synchronisées (In-Sync Replicas, ISR).

Répliques synchronisées (ISR)

Un ISR est un ensemble de répliques d'une partition considérée comme « synchronisée » (in-sync). Il y a un leader, mais il se peut qu’il n’y ait pas de suiveurs. Un suiveur est considéré comme synchronisé s'il a fait des copies exactes de tous les messages du leader avant l'expiration de l'intervalle. duplicata.lag.time.max.ms.

Un suiveur est supprimé de l'ensemble ISR s'il :

  • n'a pas fait de demande de sélection pour l'intervalle duplicata.lag.time.max.ms (presume mort)
  • n'a pas réussi à mettre à jour pendant l'intervalle duplicata.lag.time.max.ms (considéré comme lent)

Les abonnés font des demandes d'échantillonnage dans l'intervalle réplique.fetch.wait.max.ms, qui est par défaut de 500 ms.

Pour expliquer clairement le but de l'ISR, nous devons examiner les confirmations du producteur et certains scénarios d'échec. Les producteurs peuvent choisir quand le courtier envoie la confirmation :

  • acks=0, la confirmation n'est pas envoyée
  • acks=1, la confirmation est envoyée après que le leader a écrit un message dans son journal local
  • acks=all, la confirmation est envoyée une fois que toutes les répliques de l'ISR ont écrit le message dans les journaux locaux

Dans la terminologie Kafka, si l'ISR a enregistré un message, celui-ci est « validé ». Acks=all est l'option la plus sûre, mais ajoute également un délai supplémentaire. Examinons deux exemples d'échec et comment les différentes options « acks » interagissent avec le concept ISR.

Accusés de réception = 1 et ISR

Dans cet exemple, nous verrons que si le leader n’attend pas que chaque message de tous les abonnés soit enregistré, alors une perte de données est possible en cas d’échec du leader. La navigation vers un abonné non synchronisé peut être activée ou désactivée en définissant impur.leader.election.enable.

Dans cet exemple, le fabricant a la valeur acks=1. La section est répartie entre les trois courtiers. Le courtier 3 est en retard, il s'est synchronisé avec le leader il y a huit secondes et a désormais 7456 messages de retard. Le courtier 1 n’avait qu’une seconde de retard. Notre producteur envoie un message et reçoit rapidement un accusé de réception, sans le surcoût de followers lents ou morts que le leader n'attend pas.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 7. ISR avec trois répliques

Le courtier 2 échoue et le producteur reçoit une erreur de connexion. Une fois que le leadership est passé au courtier 1, nous perdons 123 messages. Le suiveur du courtier 1 faisait partie de l'ISR, mais n'était pas totalement synchronisé avec le leader lorsqu'il est tombé.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 8. Les messages sont perdus en cas de crash

En configuration bootstrap.serveurs Le fabricant a plusieurs courtiers répertoriés et peut demander à un autre courtier qui est le nouveau chef de section. Il établit ensuite une connexion avec le courtier 1 et continue d'envoyer des messages.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 9. L'envoi de messages reprend après une courte pause

Le courtier 3 est encore plus en retard. Il effectue des requêtes de récupération mais ne peut pas se synchroniser. Cela peut être dû à une connexion réseau lente entre les courtiers, à un problème de stockage, etc. Il est supprimé de l'ISR. Désormais, l'ISR se compose d'une seule réplique : le leader ! Le constructeur continue d'envoyer des messages et de recevoir des confirmations.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 10. Le suiveur du courtier 3 est supprimé de l'ISR

Le courtier 1 tombe en panne et le rôle de leader revient au courtier 3 avec la perte de 15286 XNUMX messages ! Le fabricant reçoit un message d'erreur de connexion. La transition vers un leader en dehors des ISR n'a été possible que grâce au contexte unclean.leader.election.enable=true. S'il est installé dans non, alors la transition n'aurait pas lieu et toutes les demandes de lecture et d'écriture seraient rejetées. Dans ce cas, nous attendons que le courtier 1 revienne avec ses données intactes dans la réplique, qui reprendra le leadership.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 11. Le courtier 1 tombe. Lorsqu'une panne survient, un grand nombre de messages sont perdus

Le producteur établit une connexion avec le dernier courtier et constate qu'il est désormais le leader de la section. Il commence à envoyer des messages au courtier 3.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 12. Après une courte pause, les messages sont à nouveau envoyés à la section 0

Nous avons vu qu'en dehors de courtes interruptions pour établir de nouvelles connexions et rechercher un nouveau leader, le constructeur envoyait constamment des messages. Cette configuration garantit la disponibilité au détriment de la cohérence (sécurité des données). Kafka a perdu des milliers de messages mais a continué à accepter de nouvelles écritures.

Acks = tous et ISR

Répétons encore ce scénario, mais avec accusés de réception = tous. Le Broker 3 a une latence moyenne de quatre secondes. Le fabricant envoie un message avec accusés de réception = tous, et ne reçoit plus de réponse rapide. Le leader attend que le message soit enregistré par toutes les répliques de l'ISR.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 13. ISR avec trois répliques. L'un est lent, ce qui entraîne des retards d'enregistrement

Après quatre secondes de délai supplémentaire, le courtier 2 envoie un accusé de réception. Toutes les répliques sont désormais entièrement mises à jour.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 14. Toutes les répliques enregistrent les messages et envoient un accusé de réception

Le courtier 3 prend désormais encore plus de retard et est retiré de l'ISR. La latence est considérablement réduite car il n'y a plus de répliques lentes dans l'ISR. Le courtier 2 n'attend désormais que le courtier 1, et il a un décalage moyen de 500 ms.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 15. La réplique sur le courtier 3 est supprimée de l'ISR

Puis le courtier 2 tombe et le leadership passe au courtier 1 sans perte de messages.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 16. Le courtier 2 tombe

Le constructeur trouve un nouveau leader et commence à lui envoyer des messages. La latence est encore réduite car l'ISR se compose désormais d'une seule réplique ! Par conséquent l'option accusés de réception = tous n'ajoute pas de redondance.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 17. La réplique sur le courtier 1 prend les devants sans perdre de messages

Puis le courtier 1 plante et le lead revient au courtier 3 avec une perte de 14238 XNUMX messages !

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 18. Le courtier 1 décède et la transition de leadership dans un environnement impur entraîne une perte de données importante

Nous n'avons pas pu installer l'option impur.leader.election.enable dans le sens oui. Par défaut c'est égal non. Paramètres accusés de réception = tous с unclean.leader.election.enable=true offre une accessibilité avec une sécurité supplémentaire des données. Mais comme vous pouvez le constater, nous pouvons toujours perdre des messages.

Mais que se passe-t-il si nous voulons accroître la sécurité des données ? Tu peux mettre impur.leader.election.enable = faux, mais cela ne nous protégera pas nécessairement de la perte de données. Si le leader est tombé durement et a emporté les données avec lui, les messages sont toujours perdus et la disponibilité est perdue jusqu'à ce que l'administrateur rétablisse la situation.

Il est préférable de s'assurer que tous les messages sont redondants, sinon de supprimer l'enregistrement. Ensuite, du moins du point de vue du courtier, la perte de données n'est possible qu'en cas de deux ou plusieurs pannes simultanées.

Acks=all, min.insync.replicas et ISR

Avec configuration de sujet min.insync.replicas Nous augmentons le niveau de sécurité des données. Reprenons la dernière partie du scénario précédent, mais cette fois avec min.insync.replicas=2.

Ainsi, le courtier 2 a une réplique leader et le suiveur du courtier 3 est supprimé de l'ISR.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 19. ISR à partir de deux répliques

Le courtier 2 tombe et le leadership passe au courtier 1 sans perte de messages. Mais désormais, l’ISR ne comporte qu’une seule réplique. Cela ne correspond pas au nombre minimum pour recevoir des enregistrements et le courtier répond donc à la tentative d'écriture par une erreur. Pas assez de répliques.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 20. Le nombre d'ISR est inférieur d'un à celui spécifié dans min.insync.replicas

Cette configuration sacrifie la disponibilité au profit de la cohérence. Avant d'accuser réception d'un message, nous nous assurons qu'il est écrit sur au moins deux réplicas. Cela donne beaucoup plus de confiance au fabricant. Ici, la perte de message n'est possible que si deux répliques échouent simultanément dans un court intervalle jusqu'à ce que le message soit répliqué vers un suiveur supplémentaire, ce qui est peu probable. Mais si vous êtes super paranoïaque, vous pouvez définir le facteur de réplication sur 5, et min.insync.replicas par 3. Ici, trois courtiers doivent tomber en même temps pour perdre le record ! Bien entendu, cette fiabilité se paie en latence supplémentaire.

Quand l’accessibilité est nécessaire à la sécurité des données

Comme dans cas avec RabbitMQ, l'accessibilité est parfois nécessaire pour la sécurité des données. Voici ce à quoi vous devez penser :

  • L'éditeur peut-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 la réponse est non, l’optimisation de la disponibilité améliore la sécurité des données. Vous perdrez moins de données si vous choisissez la disponibilité au lieu de ne pas enregistrer. Ainsi, tout se résume à trouver un équilibre, et la décision dépend de la situation spécifique.

La signification de l’ISR

La suite ISR vous permet de choisir l'équilibre optimal entre sécurité des données et latence. Par exemple, assurez la disponibilité en cas de panne de la majorité des répliques, en minimisant l'impact des répliques mortes ou lentes en termes de latence.

Nous choisissons nous-mêmes le sens duplicata.lag.time.max.ms selon vos besoins. Essentiellement, ce paramètre signifie le délai que nous sommes prêts à accepter lorsque accusés de réception = tous. La valeur par défaut est de dix secondes. Si cela est trop long pour vous, vous pouvez le réduire. Ensuite, la fréquence des changements dans l'ISR augmentera, car les abonnés seront supprimés et ajoutés plus souvent.

RabbitMQ est simplement un ensemble de miroirs qui doivent être répliqués. Les miroirs lents introduisent une latence supplémentaire et les miroirs morts peuvent attendre que les paquets qui vérifient la disponibilité de chaque nœud (net tick) répondent. ISR est un moyen intéressant pour éviter ces problèmes de latence. Mais nous risquons de perdre en redondance puisque les ISR ne peuvent que se réduire au leader. Pour éviter ce risque, utilisez le paramètre min.insync.replicas.

Garantie de connexion client

Dans les paramètres bootstrap.serveurs le producteur et le consommateur peuvent spécifier plusieurs courtiers pour connecter les clients. L'idée est que lorsqu'un nœud tombe en panne, il en reste plusieurs de rechange avec lesquels le client peut ouvrir une connexion. Ce ne sont pas nécessairement des chefs de section, mais simplement un tremplin pour le chargement initial. Le client peut leur demander quel nœud héberge le leader de la partition en lecture/écriture.

Dans RabbitMQ, les clients peuvent se connecter à n'importe quel nœud et le routage interne envoie la requête là où elle doit aller. Cela signifie que vous pouvez installer un équilibreur de charge devant RabbitMQ. Kafka exige que les clients se connectent au nœud qui héberge le chef de partition correspondant. Dans une telle situation, vous ne pouvez pas installer d'équilibreur de charge. Liste bootstrap.serveurs Il est essentiel que les clients puissent accéder aux nœuds appropriés et les trouver après une panne.

Architecture consensuelle de Kafka

Jusqu’à présent, nous n’avons pas réfléchi à la manière dont le cluster apprend la chute du courtier et à la manière dont un nouveau leader est élu. Pour comprendre comment Kafka fonctionne avec les partitions réseau, vous devez d'abord comprendre l'architecture de consensus.

Chaque cluster Kafka est déployé avec un cluster Zookeeper, qui est un service de consensus distribué qui permet au système de parvenir à un consensus sur un état donné, en donnant la priorité à la cohérence plutôt qu'à la disponibilité. Le consentement d'une majorité de nœuds Zookeeper est requis pour approuver les opérations de lecture et d'écriture.

Zookeeper stocke l'état du cluster :

  • Liste des sujets, sections, configuration, répliques leaders actuelles, répliques préférées.
  • Membres du cluster. Chaque courtier envoie une requête ping au cluster Zookeeper. S'il ne reçoit pas de ping dans un délai spécifié, Zookeeper enregistre le courtier comme indisponible.
  • Sélection des nœuds principaux et de rechange pour le contrôleur.

Le nœud contrôleur est l'un des courtiers Kafka chargés d'élire les dirigeants des répliques. Zookeeper envoie des notifications au contrôleur concernant l'appartenance au cluster et les modifications de sujet, et le contrôleur doit agir en fonction de ces modifications.

Par exemple, prenons un nouveau sujet avec dix partitions et un facteur de réplication de 3. Le contrôleur doit élire un leader pour chaque partition, en essayant de répartir de manière optimale les leaders entre les courtiers.

Pour chaque contrôleur de section :

  • met à jour les informations dans Zookeeper sur l'ISR et le leader ;
  • Envoie un LeaderAndISRCommand à chaque courtier qui héberge une réplique de cette partition, informant les courtiers de l'ISR et du leader.

Lorsqu'un courtier avec un leader tombe, Zookeeper envoie une notification au contrôleur et celui-ci élit un nouveau leader. Encore une fois, le contrôleur met d'abord à jour Zookeeper, puis envoie une commande à chaque courtier pour l'informer du changement de direction.

Chaque leader est responsable du recrutement des ISR. Paramètres duplicata.lag.time.max.ms détermine qui y entrera. Lorsque l'ISR change, le leader transmet de nouvelles informations à Zookeeper.

Zookeeper est toujours informé de tout changement afin qu'en cas d'échec, la direction passe en douceur à un nouveau leader.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 21. Consensus Kafka

Protocole de réplication

Comprendre les détails de la réplication vous aide à mieux comprendre les scénarios potentiels de perte de données.

Requêtes d'échantillonnage, décalage de fin de journal (LEO) et marque des hautes eaux (HW)

Nous avons considéré que les abonnés envoient périodiquement des demandes de récupération au leader. L'intervalle par défaut est de 500 ms. Cela diffère de RabbitMQ en ce sens que dans RabbitMQ, la réplication n'est pas initiée par le miroir de file d'attente mais par le maître. Le maître pousse les modifications vers les miroirs.

Le leader et tous les suiveurs enregistrent l'étiquette Log End Offset (LEO) et Highwater (HW). La marque LEO stocke le décalage du dernier message dans la réplique locale et le matériel conserve le décalage du dernier commit. N'oubliez pas que pour l'état de validation, le message doit être conservé sur toutes les répliques ISR. Cela signifie que LEO est généralement légèrement en avance sur HW.

Lorsque le leader reçoit un message, il le stocke localement. Le suiveur fait une demande de récupération en transmettant son LEO. Le leader envoie alors un lot de messages à partir de ce LEO et transmet également le HW actuel. Lorsque le leader reçoit des informations indiquant que toutes les répliques ont stocké le message au décalage donné, il déplace la marque HW. Seul le leader peut déplacer le HW, et ainsi tous les suiveurs connaîtront la valeur actuelle dans les réponses à leur demande. Cela signifie que les adeptes peuvent être à la traîne du leader, tant en termes de message que de connaissances matérielles. Les consommateurs reçoivent des messages uniquement jusqu'au matériel actuel.

Notez que « persisté » signifie écrit en mémoire et non sur le disque. Pour des raisons de performances, Kafka se synchronise sur le disque à un intervalle spécifique. RabbitMQ a également un tel intervalle, mais il enverra un accusé de réception à l'éditeur seulement après que le maître et tous les miroirs auront écrit le message sur le disque. Les développeurs de Kafka, pour des raisons de performances, ont décidé d'envoyer un accusé de réception dès que le message est écrit en mémoire. Kafka parie que la redondance compense le risque de stocker brièvement les messages acquittés en mémoire uniquement.

Échec du leader

Lorsqu'un leader tombe, Zookeeper en informe le contrôleur et celui-ci sélectionne une nouvelle réplique de leader. Le nouveau leader établit une nouvelle marque HW selon son LEO. Les adeptes reçoivent ensuite des informations sur le nouveau leader. Selon la version de Kafka, l'abonné choisira l'un des deux scénarios suivants :

  1. Il tronquera le journal local vers un matériel connu et enverra une demande au nouveau leader pour les messages après cette marque.
  2. Enverra une demande au leader pour connaître le HW au moment où il a été élu leader, puis tronquera le journal à ce décalage. Il commencera alors à effectuer des requêtes de récupération périodiques à partir de ce décalage.

Un abonné devra peut-être tronquer le journal pour les raisons suivantes :

  • Lorsqu'un leader échoue, le premier adepte de l'ensemble ISR enregistré auprès de Zookeeper remporte l'élection et devient le leader. Tous les adeptes d’ISR, bien que considérés comme « synchronisés », n’ont peut-être pas reçu de copie de tous les messages de l’ancien dirigeant. Il est tout à fait possible que l'abonné présenté ne dispose pas de la copie la plus à jour. Kafka garantit qu'il n'y a pas de divergence entre les répliques. Ainsi, pour éviter les divergences, chaque suiveur doit tronquer son log à la valeur HW du nouveau leader au moment de son élection. C'est une autre raison pour laquelle la définition accusés de réception = tous si important pour la cohérence.
  • Les messages sont périodiquement écrits sur le disque. Si tous les nœuds du cluster échouent en même temps, des répliques avec des décalages différents seront stockées sur les disques. Il est possible que lorsque les courtiers reviendront en ligne, le nouveau leader élu soit derrière ses partisans car il a été enregistré sur disque avant les autres.

Retrouvailles avec le cluster

Lorsqu'elles rejoignent le cluster, les répliques font la même chose que lorsqu'un leader échoue : elles vérifient la réplique du leader et tronquent leur journal sur son matériel (au moment de l'élection). En comparaison, RabbitMQ traite également les nœuds réunis comme complètement nouveaux. Dans les deux cas, le courtier ignore tout état existant. Si la synchronisation automatique est utilisée, le maître doit alors répliquer absolument tout le contenu actuel sur le nouveau miroir selon la méthode « laisser le monde entier attendre ». Le maître n'accepte aucune opération de lecture ou d'écriture pendant cette opération. Cette approche crée des problèmes dans les grandes files d'attente.

Kafka est un journal distribué et, en général, il stocke plus de messages qu'une file d'attente RabbitMQ, où les données sont supprimées de la file d'attente après leur lecture. Les files d'attente actives devraient rester relativement petites. Mais Kafka est un journal avec sa propre politique de conservation, qui peut définir une période de plusieurs jours ou semaines. L'approche de blocage de file d'attente et de synchronisation complète est absolument inacceptable pour un journal distribué. Au lieu de cela, les partisans de Kafka tronquent simplement leur journal de bord au HW du leader (au moment de son élection) si leur copie est en avance sur le leader. Dans le cas le plus probable, lorsque le suiveur est en retard, il commence simplement à faire des requêtes de récupération en commençant par son LEO actuel.

Les abonnés nouveaux ou rejoints commencent en dehors de l'ISR et ne participent pas aux commits. Ils travaillent simplement aux côtés du groupe, recevant les messages aussi rapidement que possible jusqu'à ce qu'ils rattrapent le leader et entrent dans l'ISR. Il n’y a pas de verrouillage et pas besoin de jeter toutes vos données.

Perte de connectivité

Kafka a plus de composants que RabbitMQ, il a donc un ensemble de comportements plus complexes lorsque le cluster est déconnecté. Mais Kafka a été initialement conçu pour les clusters, les solutions sont donc très bien pensées.

Vous trouverez ci-dessous plusieurs scénarios d'échec de connectivité :

  • Scénario 1 : Le suiveur ne voit pas le chef, mais voit quand même le gardien du zoo.
  • Scénario 2 : Le leader ne voit aucun adepte, mais voit toujours Zookeeper.
  • Scénario 3 : Le suiveur voit le chef, mais ne voit pas le gardien du zoo.
  • Scénario 4 : Le leader voit les suiveurs, mais ne voit pas le gardien du zoo.
  • Scénario 5 : le suiveur est complètement séparé des autres nœuds Kafka et de Zookeeper.
  • Scénario 6 : Le leader est complètement séparé des autres nœuds Kafka et de Zookeeper.
  • Scénario 7 : le nœud du contrôleur Kafka ne peut pas voir un autre nœud Kafka.
  • Scénario 8 : le contrôleur Kafka ne voit pas Zookeeper.

Chaque scénario a son propre comportement.

Scénario 1 : le suiveur ne voit pas le chef, mais voit toujours le gardien du zoo

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 22. Scénario 1 : ISR de trois répliques

L'échec de connectivité sépare le courtier 3 des courtiers 1 et 2, mais pas de Zookeeper. Le courtier 3 ne peut plus envoyer de requêtes de récupération. Après que le temps soit passé duplicata.lag.time.max.ms il est supprimé de l'ISR et ne participe pas aux validations de messages. Une fois la connectivité rétablie, il reprendra les requêtes de récupération et rejoindra l'ISR lorsqu'il rattrapera le leader. Zookeeper continuera à recevoir des pings et supposera que le courtier est bel et bien vivant.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 23. Scénario 1 : le courtier est supprimé de l'ISR si aucune demande d'extraction n'est reçue de sa part dans l'intervalle replica.lag.time.max.ms

Il n'y a pas de suspension de cerveau divisé ou de nœud comme dans RabbitMQ. Au lieu de cela, la redondance est réduite.

Scénario 2 : Le leader ne voit aucun adepte, mais voit toujours Zookeeper

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 24. Scénario 2. Leader et deux suiveurs

Une panne de connectivité réseau sépare le leader des suiveurs, mais le courtier peut toujours voir Zookeeper. Comme dans le premier scénario, l'ISR diminue, mais cette fois uniquement au niveau du leader, car tous les abonnés arrêtent d'envoyer des requêtes de récupération. Encore une fois, il n’y a pas de division logique. Au lieu de cela, il y a une perte de redondance pour les nouveaux messages jusqu'à ce que la connectivité soit restaurée. Zookeeper continue de recevoir des pings et pense que le courtier est bel et bien vivant.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 25. Scénario 2. L'ISR s'est réduit au seul leader

Scénario 3. Le suiveur voit le leader, mais ne voit pas le gardien de zoo

Le suiveur est séparé du Zookeeper, mais pas du courtier avec le leader. En conséquence, le suiveur continue de faire des requêtes de récupération et d'être membre de l'ISR. Zookeeper ne reçoit plus de pings et enregistre un crash de courtier, mais comme il ne s'agit que d'un suiveur, il n'y a aucune conséquence après la récupération.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 26. Scénario 3 : le suiveur continue d'envoyer des demandes de récupération au leader

Scénario 4. Le leader voit ses adeptes, mais ne voit pas le gardien de zoo

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 27. Scénario 4. Leader et deux suiveurs

Le leader est séparé du Zookeeper, mais pas des courtiers ayant des suiveurs.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 28. Scénario 4 : Leader isolé du gardien de zoo

Après un certain temps, Zookeeper enregistrera une défaillance du courtier et en informera le contrôleur. Il choisira un nouveau leader parmi ses partisans. Cependant, le leader d'origine continuera à penser qu'il est le leader et continuera à accepter les entrées de accusés de réception = 1. Les abonnés ne lui envoient plus de requêtes de récupération, il les considérera donc comme mortes et tentera de réduire l'ISR à lui-même. Mais comme il n'a pas de connexion avec Zookeeper, il ne pourra pas le faire et refusera alors d'accepter toute autre entrée.

Messages accusés de réception = tous ne recevra pas d'accusé de réception car l'ISR active d'abord toutes les répliques et les messages ne leur parviennent pas. Lorsque le leader d’origine tentera de les retirer de l’ISR, il ne pourra pas le faire et cessera d’accepter des messages.

Les clients remarquent bientôt le changement de leader et commencent à envoyer des enregistrements au nouveau serveur. Une fois le réseau restauré, le leader d'origine voit qu'il n'est plus un leader et tronque son journal à la valeur matérielle qu'avait le nouveau leader au moment de l'échec pour éviter une divergence de journal. Il commencera alors à envoyer des requêtes de récupération au nouveau leader. Tous les enregistrements du leader d'origine qui ne sont pas répliqués sur le nouveau leader sont perdus. Autrement dit, les messages qui n'ont pas été reconnus par le leader d'origine au cours des quelques secondes où deux leaders travaillaient seront perdus.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 29. Scénario 4. Le leader du courtier 1 devient un suiveur après la restauration du réseau

Scénario 5 : le suiveur est complètement séparé des autres nœuds Kafka et de Zookeeper

Le suiveur est complètement isolé des autres nœuds Kafka et de Zookeeper. Il se retire simplement des ISR jusqu'à ce que le réseau soit rétabli, puis rattrape les autres.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 30. Scénario 5 : le suiveur isolé est supprimé de l'ISR

Scénario 6 : le leader est complètement séparé des autres nœuds Kafka et de Zookeeper

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 31. Scénario 6. Leader et deux suiveurs

Le leader est complètement isolé de ses partisans, du contrôleur et du gardien de zoo. Pendant une courte période, il continuera à accepter les inscriptions de accusés de réception = 1.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 32. Scénario 6 : Isoler le leader des autres nœuds Kafka et Zookeeper

N'ayant pas reçu de demandes après expiration duplicata.lag.time.max.ms, il essaiera de réduire l'ISR à lui-même, mais ne pourra pas le faire car il n'y a pas de communication avec Zookeeper, il cessera alors d'accepter les écritures.

Pendant ce temps, Zookeeper marquera le courtier isolé comme mort et le contrôleur élira un nouveau chef.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 33. Scénario 6. Deux dirigeants

Le leader d'origine peut accepter les entrées pendant quelques secondes, mais cesse ensuite d'accepter les messages. Les clients sont mis à jour toutes les 60 secondes avec les dernières métadonnées. Ils seront informés du changement de leader et commenceront à envoyer les candidatures au nouveau leader.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 34. Scénario 6 : Les fabricants passent à un nouveau leader

Toutes les entrées confirmées effectuées par le leader d'origine depuis la perte de connectivité seront perdues. Une fois le réseau restauré, le leader d'origine découvrira grâce à Zookeeper qu'il n'est plus le leader. Ensuite, il tronquera son journal au HW du nouveau leader au moment de l'élection et commencera à envoyer des demandes en tant que suiveur.

RabbitMQ vs Kafka : tolérance aux pannes et haute disponibilité
Riz. 35. Scénario 6 : Le leader d'origine devient un suiveur une fois la connectivité réseau restaurée

Dans cette situation, une séparation logique peut se produire pendant une courte période, mais seulement si accusés de réception = 1 и min.insync.replicas également 1. La séparation logique se termine automatiquement soit après la restauration du réseau, lorsque le leader d'origine se rend compte qu'il n'est plus le leader, soit lorsque tous les clients se rendent compte que le leader a changé et commencent à écrire au nouveau leader - selon la première éventualité. Dans tous les cas, certains messages seront perdus, mais uniquement avec accusés de réception = 1.

Il existe une autre variante de ce scénario où, juste avant la scission du réseau, les partisans ont pris du retard et le leader a réduit l'ISR à lui seul. Il se retrouve alors isolé en raison de la perte de connectivité. Un nouveau leader est élu, mais le leader d'origine continue d'accepter les candidatures, même accusés de réception = tous, car il n’y a personne d’autre en ISR que lui. Ces enregistrements seront perdus une fois le réseau restauré. La seule façon d'éviter cette option est min.insync.replicas = 2.

Scénario 7 : le nœud du contrôleur Kafka ne peut pas voir un autre nœud Kafka

En général, une fois la connexion avec un nœud Kafka perdue, le contrôleur ne pourra lui transmettre aucune information de changement de leader. Dans le pire des cas, cela conduira à une séparation logique à court terme, comme dans le scénario 6. Le plus souvent, le courtier ne deviendra tout simplement pas candidat à la direction si cette dernière échoue.

Scénario 8 : le contrôleur Kafka ne voit pas Zookeeper

Zookeeper ne recevra pas de ping du contrôleur tombé et sélectionnera un nouveau nœud Kafka comme contrôleur. Le contrôleur d'origine peut continuer à se présenter comme tel, mais il ne reçoit pas de notifications de Zookeeper, il n'aura donc aucune tâche à effectuer. Une fois le réseau restauré, il se rendra compte qu’il n’est plus un contrôleur, mais qu’il est devenu un nœud Kafka classique.

Conclusions des scénarios

Nous voyons que la perte de connectivité des abonnés n'entraîne pas de perte de message, mais réduit simplement temporairement la redondance jusqu'à ce que le réseau soit restauré. Bien entendu, cela peut entraîner une perte de données si un ou plusieurs nœuds sont perdus.

Si le leader est séparé de Zookeeper en raison d'une perte de connectivité, cela pourrait entraîner la perte de messages de accusés de réception = 1. Le manque de communication avec Zookeeper provoque une brève rupture logique avec les deux dirigeants. Ce problème est résolu par le paramètre accusés de réception = tous.

Paramètre min.insync.replicas en deux ou plusieurs répliques fournit une assurance supplémentaire que de tels scénarios à court terme n'entraîneront pas de perte de messages comme dans le scénario 6.

Résumé des messages perdus

Énumérons toutes les façons dont vous pouvez perdre des données dans Kafka :

  • Tout échec du leader si les messages ont été confirmés à l'aide accusés de réception = 1
  • Toute transition impure de leadership, c'est-à-dire vers un suiveur extérieur à l'ISR, même avec accusés de réception = tous
  • Isoler le leader de Zookeeper si les messages ont été confirmés à l'aide de accusés de réception = 1
  • Isolement complet du leader qui a déjà réduit le groupe ISR à lui-même. Tous les messages seront perdus, même accusés de réception = tous. Ceci n'est vrai que si min.insync.replicas=1.
  • Pannes simultanées de tous les nœuds de partition. Étant donné que les messages sont reconnus depuis la mémoire, certains peuvent ne pas encore être écrits sur le disque. Après le redémarrage des serveurs, certains messages peuvent manquer.

Les transitions de leadership impures peuvent être évitées soit en les interdisant, soit en garantissant au moins deux licenciements. La configuration la plus durable est une combinaison accusés de réception = tous и min.insync.replicas plus 1.

Comparaison directe de la fiabilité de RabbitMQ et Kafka

Pour garantir la fiabilité et la haute disponibilité, les deux plates-formes implémentent un système de réplication primaire et secondaire. Cependant, RabbitMQ a un talon d'Achille. Lors de la reconnexion après un échec, les nœuds suppriment leurs données et la synchronisation est bloquée. Ce double coup dur remet en question la longévité des grandes files d’attente dans RabbitMQ. Vous devrez accepter soit une redondance réduite, soit des temps de blocage longs. La réduction de la redondance augmente le risque de perte massive de données. Mais si les files d'attente sont petites, dans un souci de redondance, de courtes périodes d'indisponibilité (quelques secondes) peuvent être traitées par des tentatives de connexion répétées.

Kafka n'a pas ce problème. Il rejette les données uniquement à partir du point de divergence entre le leader et le suiveur. Toutes les données partagées sont enregistrées. De plus, la réplication ne bloque pas le système. Le leader continue d'accepter des publications pendant que le nouveau suiveur rattrape son retard, donc pour les développeurs, rejoindre ou rejoindre le cluster devient une tâche triviale. Bien entendu, des problèmes subsistent, tels que la bande passante du réseau lors de la réplication. Si vous ajoutez plusieurs abonnés en même temps, vous risquez de rencontrer une limite de bande passante.

RabbitMQ est supérieur à Kafka en termes de fiabilité lorsque plusieurs serveurs d'un cluster tombent en panne en même temps. Comme nous l'avons déjà dit, RabbitMQ envoie une confirmation à l'éditeur uniquement après que le message a été écrit sur le disque par le maître et tous les miroirs. Mais cela ajoute une latence supplémentaire pour deux raisons :

  • fsync toutes les quelques centaines de millisecondes
  • La défaillance du miroir ne peut être remarquée qu'après l'expiration de la durée de vie des paquets qui vérifient la disponibilité de chaque nœud (net tick). Si le miroir ralentit ou tombe, cela ajoute un délai.

Le pari de Kafka est que si un message est stocké sur plusieurs nœuds, il peut accuser réception des messages dès qu'ils atteignent la mémoire. De ce fait, il existe un risque de perdre des messages de tout type (même accusés de réception = tous, min.insync.replicas=2) en cas de panne simultanée.

Dans l’ensemble, Kafka présente de meilleures performances logicielles et est conçu dès le départ pour les clusters. Le nombre de followers peut être augmenté jusqu'à 11 si nécessaire pour des raisons de fiabilité. Facteur de réplication 5 et nombre minimum de répliques synchronisées min.insync.replicas=3 fera de la perte de message un événement très rare. Si votre infrastructure peut prendre en charge ce taux de réplication et ce niveau de redondance, vous pouvez choisir cette option.

Le clustering RabbitMQ convient aux petites files d'attente. Mais même les petites files d’attente peuvent s’allonger rapidement en cas de trafic intense. Lorsque les files d’attente deviennent importantes, vous devrez faire des choix difficiles entre disponibilité et fiabilité. Le clustering RabbitMQ est mieux adapté aux situations non typiques dans lesquelles les avantages de la flexibilité de RabbitMQ l'emportent sur les inconvénients de son clustering.

Un antidote à la vulnérabilité de RabbitMQ aux grandes files d'attente consiste à les diviser en plusieurs files d'attente plus petites. Si vous n'exigez pas un classement complet de toute la file d'attente, mais uniquement les messages pertinents (par exemple, les messages d'un client spécifique), ou si vous ne commandez rien du tout, alors cette option est acceptable : regardez mon projet Rééquilibreur pour diviser la file d'attente (le projet en est encore à ses débuts).

Enfin, n'oubliez pas un certain nombre de bugs dans les mécanismes de clustering et de réplication de RabbitMQ et de Kafka. Au fil du temps, les systèmes sont devenus plus matures et plus stables, mais aucun message ne sera jamais à 100 % à l’abri d’une perte ! De plus, des accidents à grande échelle se produisent dans les centres de données !

Si j'ai raté quelque chose, fait une erreur ou si vous n'êtes pas d'accord avec l'un des points, n'hésitez pas à écrire un commentaire ou à me contacter.

On me demande souvent : « Que choisir, Kafka ou RabbitMQ ? », « Quelle plateforme est la meilleure ? ». La vérité est que cela dépend vraiment de votre situation, de votre expérience actuelle, etc. J'hésite à donner mon avis car ce serait trop simpliste de recommander une seule plateforme pour tous les cas d'utilisation et les limitations possibles. J'ai écrit cette série d'articles pour que vous puissiez vous faire votre propre opinion.

Je tiens à dire que les deux systèmes sont leaders dans ce domaine. Je suis peut-être un peu partial car, d'après mon expérience des projets, j'ai tendance à valoriser des choses comme l'ordre garanti des messages et la fiabilité.

Je vois d'autres technologies qui manquent de cette fiabilité et de cette garantie de commande, puis je regarde RabbitMQ et Kafka et je réalise l'incroyable valeur de ces deux systèmes.

Source: habr.com

Ajouter un commentaire