La bonne façon d'ouvrir RocketMQ, ne dites pas que vous ne connaissez pas RocketMQ après l'avoir lu

Introduction à RocketMQ

Apache RocketMQ est un middleware de messagerie distribué avec une faible latence, une concurrence élevée, une haute disponibilité et une fiabilité élevée. La file d'attente de messages RocketMQ peut fournir des capacités de découplage asynchrone et de réduction des pics et de remplissage des vallées pour les systèmes d'applications distribués.

Concept RocketMQ

  • Sujet: Sujet de message, utilisé pour classer un type de message, tel qu'un sujet de commande, c'est-à-dire que tous les messages liés à la commande peuvent être véhiculés par ce sujet, et le producteur envoie des messages à ce sujet.
  • Producteur: rôle responsable de la production des messages et de leur envoi à Topic.
  • Consommateur: rôle responsable de la réception et de la consommation des messages du sujet.
  • Message: Le contenu envoyé par le producteur au sujet sera consommé par le consommateur.
  • Attributs de message: le producteur peut personnaliser certains attributs liés à l'entreprise pour le message lors de l'envoi, tels que la clé et l'étiquette de message.
  • Groupe: Type de producteur ou de consommateur, ce type de producteur ou de consommateur produit ou consomme généralement le même type de message, et la logique de publication ou d'abonnement de message est cohérente.

Pourquoi utiliser RocketMQ?

Découplage asynchrone

Avec la popularité de l'architecture de microservices, il est très important de trier la relation entre les services. Le découplage asynchrone peut réduire le degré de couplage entre les services, tout en augmentant également le débit des services.

Il existe de nombreux scénarios d'entreprise qui utilisent le découplage asynchrone, car l'activité de chaque industrie sera différente et je crois que tout le monde peut le comprendre avec des entreprises plus courantes.

Par exemple, dans le scénario commercial de passer une commande dans le secteur du commerce électronique, le processus de commande le plus simple est le suivant:

  1. Verrouiller l'inventaire
  2. Créer une commande
  3. Paiement utilisateur
  4. Déduction d'inventaire
  5. Envoyer une notification d'achat par SMS aux utilisateurs
  6. Ajouter des points aux utilisateurs
  7. Aviser le marchand d'expédier

Une fois notre commande passée, l'utilisateur effectuera un paiement. Une fois le paiement terminé, il y aura une logique appelée rappel de paiement, et une logique métier doit être effectuée dans le rappel. Regardez d'abord le temps de synchronisation, comme indiqué ci-dessous:

Le processus de commande ci-dessus de 3 à 5 peut être traité dans un processus asynchrone.Pour l'utilisateur, une fois le paiement terminé, il n'a pas besoin de prêter attention au processus suivant. Un traitement lent en arrière-plan suffit, ce qui peut simplifier les trois étapes et améliorer le temps de traitement des rappels.

Coupe de pic et remplissage de vallée

Le rasage des pics et le remplissage des vallées signifient que sous l'impact d'un trafic important, RocketMQ peut résister à un trafic important instantané, protéger la stabilité du système et améliorer l'expérience utilisateur.

Dans le secteur du commerce électronique, l'impact le plus courant sur le trafic est l'activité de pointe. L'utilisation de RocketMQ pour réaliser une activité de pointe complète représente encore beaucoup de travail à faire. Cela dépasse le cadre de cet article. J'ai l'occasion de parler avec vous seul plus tard. Ce que je veux vous dire, c'est que des scénarios comme celui-ci peuvent utiliser RocketMQ pour gérer une forte concurrence, à condition que le scénario d'entreprise prenne en charge le traitement asynchrone .

Cohérence éventuelle des transactions distribuées

Comme nous le savons tous, les transactions distribuées ont 2PC, TCC, une cohérence éventuelle et d'autres solutions. Parmi eux, l'utilisation de files d'attente de messages pour d'éventuelles solutions de cohérence est plus couramment utilisée.

Dans le scénario commercial du commerce électronique, l'activité principale liée aux transactions doit garantir la cohérence des données. En introduisant la transaction distribuée de la version RocketMQ de la file d'attente de messages, le découplage entre les systèmes peut être réalisé et la cohérence finale des données peut être assurée.

Distribution des données

La distribution des données fait référence à la capacité de distribuer les données d'origine à plusieurs systèmes qui doivent utiliser ces données pour atteindre l'hétérogénéité des données. Le plus courant est de distribuer des données à ES, Redis pour fournir des services tels que la recherche et la mise en cache pour les entreprises.

En plus de la distribution manuelle des données via le mécanisme de messagerie, vous pouvez également vous abonner au binlog de Mysql pour le distribuer. Dans ce scénario, vous devez utiliser les messages séquentiels de RocketMQ pour assurer la cohérence des données.

Architecture RocketMQ

Source de l'image Document officiel d'Alibaba Cloud

  • Serveur de noms: C'est un nœud presque sans état qui peut être déployé en clusters. Il fournit des services de nommage dans la version RocketMQ de la file d'attente de messages, la mise à jour et la découverte des services Broker. C'est un registre.
  • Courtier: rôle de relais de messages, responsable du stockage et du transfert des messages. Il est divisé en un courtier maître et un courtier esclave. Un courtier maître peut correspondre à plusieurs courtiers esclaves, mais un courtier esclave ne peut correspondre qu'à un courtier maître. Une fois que le courtier a démarré, il doit effectuer une opération d'enregistrement sur le serveur de noms; puis, il signale régulièrement les informations de routage des sujets au serveur de noms toutes les 30 secondes.
  • Producteur: Établissez un lien long (Keep-alive) avec l'un des nœuds du cluster de serveurs de noms (de manière aléatoire), lisez périodiquement les informations de routage des sujets à partir du serveur de noms et établissez un lien long vers le courtier principal qui fournit des services de sujets, et faites régulièrement des rapports au maître Le courtier envoie un battement de cœur.
  • Consommateur: établissez une longue connexion avec l'un des nœuds du cluster de serveurs de noms (de manière aléatoire), extrayez régulièrement les informations de routage des rubriques du serveur de noms et établissez une longue connexion avec le courtier maître et le courtier esclave qui fournissent des services de rubrique, et l'envoyez régulièrement au courtier principal, Slave Broker envoie un battement de cœur. Les consommateurs peuvent s'abonner aux messages du courtier principal ou du courtier esclave. Les règles d'abonnement sont déterminées par la configuration du courtier.

Type de message RocketMQ

RocketMQ prend en charge les types de messages riches, qui peuvent répondre aux besoins commerciaux de plusieurs scénarios. Différents messages ont des scénarios d'application différents. Voici quatre types de messages couramment utilisés.

Les nouvelles générales

Les messages courants font référence aux messages sans caractéristiques dans RocketMQ. Lorsqu'il n'y a pas de scénario métier particulier, les messages ordinaires suffisent. S'il existe des scénarios spéciaux, vous pouvez utiliser des types de messages spéciaux, tels que séquence, transaction, etc.

Envoyer de manière synchrone

Envoi synchrone: l'expéditeur du message envoie un message et le résultat renvoyé par le serveur sera synchronisé.

Envoi asynchrone

Envoi asynchrone: l'expéditeur du message envoie un message sans attendre que le serveur renvoie le résultat et peut envoyer le message suivant. L'expéditeur peut recevoir la réponse du serveur via l'interface de rappel et traiter le résultat de la réponse.

Envoi unidirectionnel

Envoi unidirectionnel: l'expéditeur du message est seul responsable de l'envoi du message, et après l'envoi, la vitesse d'envoi est très rapide et il y a un risque de perdre le message.

Message séquentiel

La messagerie séquentielle signifie que les producteurs publient les messages dans un certain ordre; les consommateurs s'abonnent aux messages dans un ordre prédéterminé, c'est-à-dire que les messages publiés en premier seront reçus en premier par les consommateurs.

Par exemple, dans le scénario de distribution de données, si nous souscrivons au binlog de Mysql pour l'hétérogénéité des données. Si les messages sont dans le désordre, il y aura un désordre des données.

Par exemple, ajoutez un élément de données avec id = 1, puis supprimez-le immédiatement. Cela entraîne deux messages. La séquence de consommation normale consiste à ajouter d'abord, puis à supprimer, à ce stade, il n'y a pas de données. Si les messages ne sont pas dans l'ordre, les messages supprimés sont consommés en premier, puis les nouveaux ajoutés sont consommés. À ce stade, les données sont toujours là et non supprimées, ce qui entraînera des incohérences.

Message chronométré

Message chronométré signifie que le message a la fonction d'envoi chronométré. Lorsque le message est envoyé au serveur, il ne sera pas remis au consommateur immédiatement. Au lieu de cela, le message ne sera pas remis aux consommateurs pour consommation avant l'heure spécifiée par le message.

Les messages retardés sont également des messages programmés. Les messages programmés sont programmés pour être envoyés à un moment donné, tel que le 11/11/2020 à 12 h 00.

Les messages retardés sont généralement basés sur l'heure d'envoi actuelle en fonction de la durée d'envoi du délai. Par exemple, l'heure actuelle est 2020-09-10 12:00:00 et le délai est de 10 minutes, puis le message sera envoyé le 2020-09-10 12:10 une fois le message envoyé. : 00 pour la livraison aux consommateurs.

Les messages chronométrés peuvent être utilisés dans des scénarios tels que l'annulation automatique des commandes sans paiement après l'expiration du délai.

Message de transaction

RocketMQ fournit une fonction de transaction distribuée similaire à X / Open XA. Grâce aux messages de transaction RocketMQ, la cohérence finale des transactions distribuées peut être obtenue.

Processus interactif:

Source de l'image Document officiel d'Alibaba Cloud

  1. L'expéditeur envoie d'abord un message semi-transactionnel au serveur RocketMQ.
  2. Une fois que le serveur RocketMQ a reçu le message et persiste avec succès, il renvoie un Ack à l'expéditeur pour confirmer que le message a bien été envoyé. À ce stade, le message est un message semi-transactionnel et ne sera pas remis au consommateur.
  3. Après avoir reçu l'accusé de réception du message semi-transactionnel, l'expéditeur commence à exécuter la logique de transaction locale.
  4. L'expéditeur soumet une deuxième confirmation au serveur en fonction du résultat de l'exécution de la transaction locale. Si la transaction locale est exécutée avec succès, le message est validé, si l'exécution échoue, le message est annulé et le serveur reçoit l'état de validation et marque le message semi-transactionnel comme livrable. , Le consommateur finira par recevoir le message; le serveur supprimera le message semi-transactionnel lorsqu'il recevra l'état de restauration et le consommateur ne recevra pas le message.
  5. Si une situation inattendue se produit, il n'y a pas de seconde confirmation du message à l'étape 4, et le serveur lancera une contre-vérification de message pour le message après avoir attendu pendant un temps fixe.
  6. Après avoir reçu le message, l'expéditeur doit vérifier le résultat final de l'exécution de la transaction locale du message correspondant. L'expéditeur soumet à nouveau la deuxième confirmation en fonction de l'état final de la transaction locale obtenu par l'inspection, et le serveur effectue toujours des opérations sur le message de demi-transaction selon l'étape 4.

Les meilleures pratiques

Nouvelle tentative de message

Une fois que le message n'a pas été consommé par le consommateur, le serveur RocketMQ re-délivrera le message, sachant que le consommateur a réussi à consommer le message, bien sûr, il y a une limite au nombre de tentatives, 16 par défaut.

La nouvelle tentative de message garantit que le message n'est pas perdu dans une certaine mesure et la consommation finale est obtenue par une nouvelle tentative. Il convient de noter que lorsque les consommateurs consomment, ils doivent attendre le succès de l'entreprise locale avant ACK (confirmation de consommation), sinon un échec de consommation se produira, mais l'ACK a déjà été effectué et le message ne sera pas remis à plusieurs reprises.

Si vous utilisez une consommation asynchrone, vous devez effectuer une conversion asynchrone et attendre que l'opération asynchrone termine le ACK. Pour plus de détails, reportez-vous à un article que j'ai écrit précédemment https://mp.weixin.qq.com/s/Bbh1GDpmkLhZhw5f0POJ2A.

Enfin, vous devez effectuer la surveillance correspondante. Si vous réessayez 4 ou 5 fois, cela échoue toujours. Fondamentalement, les tentatives suivantes échouent également. À ce stade, vous devez informer le développeur que le traitement manuel est une intervention manuelle. Ou surveillez directement la file d'attente de lettres mortes.

Filtrage des messages

Objet du message, généralement utilisé pour la classification unifiée d'un type de message. Par exemple, l'objet de la commande, mais les messages sous la commande seront divisés en plusieurs types. Par exemple, créer une commande, annuler une commande, etc.

Différents types de messages ont des processus métier différents. Nous pouvons définir le format de message de manière uniforme, puis utiliser un champ pour distinguer les types de messages afin d'appliquer une logique métier différente. Le mauvais point est que tous les messages seront envoyés au consommateur et ne pourront pas être consommés à la demande.

Dans RocketMQ, vous pouvez attribuer des balises aux messages et distinguer les types de messages par balise. Les consommateurs peuvent effectuer un filtrage des messages sur le serveur RocketMQ basé sur des balises pour s'assurer que les consommateurs ne consomment que les types de messages qui leur tiennent à cœur.

Une fois, j'ai rencontré une balise qui n'était pas utilisée correctement, il n'y avait qu'une seule instance MQ et des balises ont été utilisées pour distinguer l'environnement. Tous les messages sont dans une rubrique, l'environnement de test consomme la balise de l'environnement de test et la balise consommateur en ligne est en ligne.

Le problème avec cette approche est que les messages ne sont pas isolés et que les messages en ligne et hors ligne sont tous ensemble. L'autre est que les balises sont fixées comme une distinction entre les environnements et ne peuvent pas être utilisées dans les scénarios de type de message. Par conséquent, plusieurs rubriques ne peuvent être créées que pour véhiculer plusieurs types de messages professionnels.

Modèle de consommation

Il existe deux modes de consommation pour RocketMQ, la consommation de cluster et la consommation de diffusion.

Consommation du cluster:

Les consommateurs déploient plusieurs instances, que nous appelons un cluster, et la consommation du cluster ne sera consommée que par l'une des instances.

Convient à la plupart des scénarios d'entreprise. Dans la plupart des scénarios, notre message ne peut être utilisé qu'une seule fois et un seul consommateur peut le consommer. Par exemple, dans le scénario de rappel de paiement, si un message est consommé par plusieurs instances à la fois, il y aura consommation simultanée. Pour modifier le statut de la commande et pour déduire l'inventaire.

Consommation de diffusion:

La consommation de diffusion fera que chaque instance du cluster sera consommée une fois.

Par exemple, nous utilisons un cache local. Lorsque les données changent, nous devons actualiser le cache local de chaque nœud, de sorte que chaque nœud doit recevoir un message.

Idempotence de consommation

Le problème idempotent se produit à la fois dans le scénario de demande d'API et dans le scénario de consommation de messages. Un message ne peut pas être consommé plusieurs fois de manière répétée. Cela doit être garanti, car nous ne pouvons pas garantir que l'expéditeur du message ne l'enverra pas plusieurs fois, ni garantir que le message ne sera pas remis à plusieurs reprises.

La sémantique de livraison Exactly-Once de RocketMQ est utilisée pour résoudre des problèmes idempotents. Exactement une fois signifie que le message envoyé au système de messagerie ne peut être traité par le consommateur et traité qu'une seule fois. Même si le producteur qui réessaye l'envoi du message entraîne la remise répétée d'un message, le message ne sera consommé qu'une seule fois sur le consommateur.

La meilleure méthode de traitement idempotent nécessite toujours un identifiant d'entreprise unique. Bien que chaque message possède un MessageId, il n'est pas recommandé d'utiliser MessageId pour effectuer des jugements idempotents. Lors de l'envoi de messages, vous pouvez définir un MessageKey pour chaque message. Cette MessageKey peut être utilisée pour identifier de manière unique l'entreprise.

Je n’entrerai pas dans les détails sur la façon de gérer l’idempotence. Vous pouvez vous référer à un article que j'ai écrit avant https://mp.weixin.qq.com/s/9fhqnbeXPz7-7x0Eadd8DA, un schéma d'implémentation idempotent général.

Encapsulation des messages de transaction locale

Le message de transaction a été présenté ci-dessus. Le message de transaction de RocketMQ adopte la méthode de validation en deux phases. Et combiné avec le mécanisme de contre-vérification des messages pour assurer la cohérence finale.

Du point de vue de l'utilisation, chaque scénario métier doit implémenter une logique de contre-vérification, ce qui est un peu gênant.

Voici une autre méthode fréquemment utilisée, à savoir les messages de transaction locale. La table des messages locaux a été proposée à l'origine par eBay. Les messages de transaction locale doivent créer une table des messages dans la base de données correspondant au service. Lors de l'envoi d'un message, le message n'est pas réellement envoyé à MQ, mais les données du message sont insérées dans la table des messages.

L'action insérée est la même transaction que la logique métier locale. Si la transaction locale est exécutée avec succès, le message sera supprimé et envoyé à MQ. Si la transaction locale échoue, les données du message seront annulées.

Ensuite, vous avez besoin d'un programme spécial pour extraire les messages non envoyés dans la table des messages et les remettre à MQ. Si la remise échoue, vous pouvez réessayer jusqu'à ce qu'elle réussisse ou une intervention manuelle.

Le message est écrit dans la table des messages, puis envoyé à MQ en permanence. Cette étape ne pose aucun problème. Si après que MQ a reçu le message, le courtier est en panne alors que le message est toujours dans PageCache et le message est perdu à ce moment. Bien sûr, vous pouvez également utiliser le clignotement synchrone pour éviter les pertes. Si nous vidons le disque de manière asynchrone, existe-t-il un moyen de garantir que le message n'est pas perdu?

Comme nous l'avons mentionné précédemment, les messages de transaction RocketMQ auront un mécanisme de contre-vérification, et la méthode de table de message a également besoin d'un mécanisme pour s'assurer que le message est consommé, sinon il devra constamment réessayer d'envoyer le message jusqu'à ce que le message soit consommé.

Il doit y avoir un champ dans la table des messages pour identifier l'état actuel du message, tel que non envoyé, envoyé et consommé. Lorsque le message n'est toujours pas envoyé, il sera envoyé à MQ. Si l'envoi réussit, l'état est envoyé. Mais après quelques minutes, le statut est toujours envoyé, cette fois nous devons faire quelques actions.

Dans ce scénario, il est possible que les consommateurs ne puissent pas suivre la vitesse de production et que les messages se soient accumulés, ce qui entraîne des messages qui n'ont pas été consommés. Une autre possibilité est que le message soit perdu?

Vous pouvez obtenir les données d'accumulation de message correspondantes pour déterminer si le message s'est accumulé, sinon renvoyer le message à MQ, sachant que le message est consommé.

Le problème est que le message a été consommé, comment le savoir?

Comme le service cloud que j'utilise, il existe une API ouverte correspondante qui peut directement interroger la piste des messages. Il devrait également y avoir une version open source. Sans une étude approfondie, elle devrait être similaire à la version commerciale.

Selon la trajectoire du message, vous pouvez savoir si le message a été consommé et le processus se termine ici. Si le message envoyé à MQ échoue, il sera retenté. Si le message n'est pas consommé pendant une longue période, il sera renvoyé. Même s'il entre finalement dans la file d'attente de lettres mortes, il peut être intervenu manuellement via la surveillance de la file d'attente de lettres mortes. Ce sera certainement la cohérence finale.

Par rapport au message de transaction intégré, la méthode de table de messages locale n'a pas besoin d'implémenter la logique de rétro-vérification, mais il est gênant d'augmenter la table de messages et de prendre également en charge diverses logiques d'envoi et de vérification. Surtout lorsque la quantité de messages est importante, l'envoi rapide des messages dans la table de messages nécessite beaucoup de traitement.L'interrogation de recherche de table simple ne convient pas pour de grandes quantités.

Les deux méthodes peuvent être utilisées, tant que l'objectif que nous voulons peut être atteint.

Le mot de code n'est pas facile, faites attention si vous le pouvez, merci!

Si vous pensez que cet article vous est utile, vous pouvez l'aimer et le suivre pour le soutenir, ou vous pouvez suivre mon compte public, il y a plus d'articles techniques sur les produits secs et le partage d'informations connexes, tout le monde peut apprendre et progresser ensemble!

 

Je suppose que tu aimes

Origine blog.csdn.net/weixin_50205273/article/details/108598812
conseillé
Classement