Cet article explique d’abord quels problèmes le middleware de messages doit généralement résoudre, les difficultés rencontrées pour résoudre ces problèmes, si Apache RocketMQ peut être résolu en tant que middleware de messages distribués à haute performance et à haut débit open source par Alibaba, et comment ces problèmes sont définis dans la spécification. Cet article présentera ensuite la conception architecturale de RocketMQ, afin d’offrir aux lecteurs une compréhension rapide de RocketMQ. 1. Quels problèmes le middleware de messages doit-il résoudre ? Publier/S’abonner est la fonction la plus basique du middleware de messages et est également relative à la communication RPC traditionnelle. Je ne vais pas entrer dans les détails ici. La priorité décrite dans la spécification de priorité de message fait référence à une file d’attente de messages, chaque message a une priorité différente, généralement décrite par des entiers, le message à haute priorité est livré en premier, si le message est entièrement dans une file mémoire, il peut alors être trié selon la priorité avant la livraison, de sorte que la priorité élevée soit livrée en premier. Comme tous les messages dans RocketMQ sont persistants, s’ils sont triés selon la priorité, la surcharge sera très importante, donc RocketMQ ne prend pas spécifiquement en charge la priorité des messages, mais peut implémenter des fonctions similaires dans une solution de contournement, c’est-à-dire configurer une file d’attente à haute priorité et une file d’attente à priorité normale, et envoyer différentes priorités à différentes files d’attente. Pour les questions prioritaires, elles peuvent être résumées en 2 catégories :
- Tant que la priorité est atteinte, elle n’en est pas une au sens strict, et la priorité est généralement divisée en niveaux élevé, moyen, bas ou plusieurs autres niveaux. Chaque priorité peut être représentée par un sujet différent, et lors de l’envoi d’un message, spécifier différents sujets pour représenter la priorité, ce qui peut résoudre la plupart des problèmes de priorité, mais compromettre la précision des priorités métier.
- Priorité stricte, la priorité s’exprime comme un entier, comme 0 ~ 65535, ce type de problème de priorité n’est généralement pas adapté à être résolu avec différents sujets. Si vous voulez que MQ résolve ce problème, cela aura un impact très important sur les performances de MQ. Voici un point pour s’assurer que l’entreprise a vraiment besoin de cette hiérarchie stricte, et si les priorités sont réduites à quelques-unes, quel impact cela aura-t-il sur l’entreprise ?
L’ordre des messages fait référence à un type de message qui peut être consommé dans l’ordre dans lequel il est envoyé. Par exemple, une commande génère 3 messages, à savoir la création de la commande, le paiement de la commande et la finalisation de la commande. Lorsqu’on consomme, il est significatif de consommer dans cet ordre. Mais en même temps, les commandes peuvent être consommées en parallèle. RocketMQ peut garantir strictement que les messages sont ordonnés. Filtrage des messages Filtrage des messages Dans Broker, le filtrage selon les besoins du consommateur a l’avantage de réduire la transmission de messages inutiles au consommateur. L’inconvénient est qu’il augmente la charge du courtier et est relativement complexe à mettre en œuvre. 1. Taobao Notify prend en compte une variété de méthodes de filtrage, y compris le filtrage direct par type de message et le filtrage flexible des expressions syntaxiques, qui peut répondre presque aux besoins de filtrage les plus exigeants. 2. Taobao RocketMQ prend en charge le filtrage par simple balise de message, ainsi que par l’en-tête et le corps du message. 3. Le filtrage flexible des expressions syntaxiques est également pris en charge dans la spécification de notification CORBA. Filtrage des messages côté consommateur Ce filtrage peut être entièrement personnalisé par l’application, mais l’inconvénient est que beaucoup de messages inutiles sont envoyés au consommateur. Il existe plusieurs méthodes de persistance courantes utilisées par la persistance des messages :
- Persistez vers une base de données, comme Mysql.
- Persister vers le stockage KV, tel que levelDB, Berkeley DB et d’autres systèmes de stockage KV.
- Persistance sous forme d’enregistrements de fichiers, tels que Kafka, RocketMQ
- Créer une image persistante des données mémoire, comme Beanstalkd, VisiNotify
- (1), (2) et (3) les trois méthodes de persistance ont la capacité d’étendre le tampon de file mémoire, et (4) ne sont qu’une image mémoire, qui peut toujours restaurer les données de la mémoire précédente après que le courtier raccroche et redémarre.
Les spécifications JMS et CORBA Notification ne précisent pas explicitement comment persister, mais la performance de la partie persistance détermine directement la performance de l’ensemble du middleware message. RocketMQ exploite pleinement le cache mémoire du système de fichiers Linux pour améliorer les performances. Il existe plusieurs situations dans lesquelles la fiabilité des messages affecte la fiabilité des messages :
- Le courtier conclut normalement
- Effondrement du courtier
- Plantage du système d’exploitation
- La machine perd l’alimentation, mais l’alimentation peut être rétablie immédiatement.
- La machine ne s’allume pas (elle peut être endommagée sur des dispositifs clés comme le CPU, la carte mère, la mémoire, etc.)
- Dommages au disque.
(1), (2), (3) et (4) sont toutes des situations où les ressources matérielles peuvent être récupérées immédiatement, et RocketMQ peut s’assurer que les messages ne sont pas perdus ou qu’une petite quantité de données est perdue (selon que la méthode de flashing soit synchrone ou asynchrone). (5) (6) Il s’agit d’un point de défaillance unique et ne peut pas être récupéré, une fois qu’il se produit, tous les messages sur ce point unique sont perdus. Dans les deux cas, RocketMQ garantit que 99 % des messages ne sont pas perdus par réplication asynchrone, mais il reste très peu de messages qui peuvent être perdus. La technologie synchrone d’écriture double peut complètement éviter des points uniques, ce qui affectera inévitablement les performances, la rendant adaptée aux situations nécessitant des exigences de fiabilité des messages extrêmement élevées, comme les applications liées à la monnaie. RocketMQ prend en charge l’écriture synchrone double à partir de la version 3.0. La messagerie à faible latence peut atteindre le consommateur immédiatement après que le message soit arrivé au courtier sans accumulation de messages. RocketMQ utilise une méthode de sondage long pour garantir que le message est très en temps réel, et que le message en temps réel n’est pas inférieur à celui du push. Au moins une fois signifie que chaque message doit être livré une fois. RocketMQ Consumer capte d’abord le message dans la zone locale, puis renvoie l’ack au serveur une fois la consommation terminée. Exactement une seule fois- L’étape d’envoi de messages n’autorise pas l’envoi de messages en double.
- À l’étape Consommer Message, les messages en double ne sont pas autorisés à être consommés.
Ce n’est que lorsque les deux conditions ci-dessus sont remplies que le message peut être considéré comme « Exactement une seule fois », et pour atteindre ces deux points, une charge excessive sera inévitablement générée dans l’environnement du système distribué. Par conséquent, pour viser des performances élevées, RocketMQ ne garantit pas cette fonctionnalité et nécessite une déduplication dans l’entreprise, ce qui signifie que les messages des consommateurs doivent être idempotents. Bien que RocketMQ ne puisse pas garantir strictement la non-duplication, dans des circonstances normales, il y a rarement des envois et des consommations répétées, seulement des anomalies réseau, des démarrages et arrêts des consommateurs, ainsi que d’autres situations anormales telles que la duplication des messages. La raison essentielle de ce problème est qu’il y a de l’incertitude dans les appels réseau, c’est-à-dire le troisième état de ni succès ni d’échec, ce qui fait que le problème de la répétition des messages se pose. Que dois-je faire si le tampon du courtier est plein ? Le tampon du courtier fait généralement référence à la taille du tampon mémoire d’une file d’attente dans le courtier, qui est généralement limitée en taille, que se passe-t-il si le tampon est plein ? Voici comment cela est géré dans la spécification de notification CORBA :
- RejectNewEvents rejette le nouveau message et renvoie le code d’erreur RejectNewEvents au producteur.
- Rejetez les messages existants selon une politique spécifique
- AnyOrder - Tout événement peut être défaussé lors du surbordement. C’est le réglage par défaut pour cette propriété.
- FifoOrder - Le premier événement reçu sera le premier défaussé.
- LifoOrder - Le dernier événement reçu sera le premier défaussé.
- Ordre de priorité - Les événements doivent être défaussés dans l’ordre de priorité, de sorte que les événements de priorité inférieure soient défaussés avant les événements de priorité supérieure.
- Ordre de la date limite - Les événements doivent être éliminés dans l’ordre de la date limite la plus courte en premier.
RocketMQ ne possède pas le concept de mémoire tampon, et les files d’attente de RocketMQ sont des disques persistants, les données étant régulièrement effacées. Pour résoudre ce problème, RocketMQ présente une différence très significative par rapport aux autres MQ : le tampon mémoire de RocketMQ est abstrait en une file d’attente de longueur infinie, peu importe la quantité de données qui entre, il peut être installé, cette infinité est prémissée, le courtier supprime régulièrement les données expirées, par exemple, il ne sauvegarde que 3 jours de messages, puis bien que la longueur de ce tampon soit infinie, les données d’il y a 3 jours seront supprimées de la fin de la file. La consommation rétrospective fait référence au message que le consommateur a consommé avec succès, et que ce message doit être reconsommé en raison de la demande de l’entreprise. Par exemple, en raison de la défaillance du système consommateur, les données d’il y a une heure doivent être reconsommées après la récupération, puis le courtier doit fournir un mécanisme pour inverser la progression de la consommation selon la dimension temporelle. RocketMQ prend en compte la consommation rétrospective basée sur le temps, avec une dimension temporelle précise en millisecondes, pouvant être remontée vers l’avant ou vers l’arrière. La fonction principale du middleware de mise en question est le découplage asynchrone, et une autre fonction importante est de bloquer le pic de flood de données du front-end et d’assurer la stabilité du système back-end, qui exige que le middleware de messages ait une certaine capacité de stacking de messages, et le tas de messages intègre les deux situations suivantes :
- Les messages sont empilés dans des tampons mémoire mémoire, et une fois qu’ils dépassent le tampon mémoire, les messages peuvent être supprimés selon une certaine politique de suppression, comme décrit dans la spécification de notification CORBA. Il convient aux services capables de tolérer la défausse des messages, dans ce cas, la capacité d’accumulation des messages réside principalement dans la taille du tampon mémoire, et la dégradation des performances ne sera pas trop importante après l’empilement du message, car la quantité de données en mémoire a un impact limité sur la capacité d’accès offerte au monde extérieur.
- Les messages sont empilés dans des systèmes de stockage persistants tels que DB, KV Storage, format d’enregistrement de fichier. Lorsque les messages ne peuvent pas être touchés dans le cache mémoire, il est inévitable d’accéder au disque, ce qui génère une grande quantité d’IO en lecture, et le débit des entrées en lecture détermine directement la capacité d’accès des messages après leur accumulation.
Il y a quatre points principaux pour évaluer la capacité d’accumulation de messages :
- Combien de messages peut-on empiler, combien d’octets ? C’est-à-dire la capacité de tas du message.
- Après qu’un message est empilé, le débit du message est-il affecté par l’empilement ?
- La consommation normale des consommateurs sera-t-elle affectée après l’accumulation de messages ?
- Après que les messages sont empilés, quel est le débit lors de l’accès à des messages empilés sur le disque ?
Transactions distribuées Plusieurs spécifications connues des transactions distribuées, telles que XA, JTA, etc. Parmi eux, la spécification XA est largement prise en charge par les principaux fournisseurs de bases de données, tels qu’Oracle, Mysql, etc. Parmi eux, le leader de la mise en œuvre de la MT de XA, tel qu’Oracle Tuxedo, est largement utilisé dans la finance, les télécommunications et d’autres domaines. Les transactions distribuées impliquent des problèmes de validation en deux étapes, et en termes de stockage de données, le stockage KV doit être pris en charge, car la seconde étape du retour en arrière de commit doit modifier l’état du message, ce qui implique l’action de trouver le message selon la clé. RocketMQ contourne le problème de trouver le message selon la clé dans la deuxième étape, en utilisant la première étape pour envoyer le message préparé, obtenir le décalage du message, et la deuxième étape pour accéder au message via le décalage et modifier l’état ; l’offset est l’adresse des données. La méthode d’implémentation des transactions de RocketMQ ne se fait pas via le stockage KV, mais via la méthode du décalage, qui présente un défaut important : modifier les données par décalage entraîne trop de pages sales dans le système, ce qui nécessite une attention particulière. Messages planifiés Les messages planifiés signifient que les messages ne peuvent pas être consommés par les consommateurs immédiatement après leur envoi au courtier, et ne peuvent être consommés qu’à un moment précis ou après avoir attendu un certain temps. Si vous souhaitez soutenir une précision temporelle arbitraire, au niveau du courtier, vous devez faire du tri des messages, et si la persistance est impliquée, alors le tri des messages entraînera inévitablement une énorme surcharge de performance. RocketMQ prend en charge les messages de synchronisation, mais ne supporte pas la précision temporelle arbitraire, et prend en charge des niveaux spécifiques, tels que le chronométrage en 5, 10, 1m, etc. Réessayer le message Après que le consommateur n’ait pas consommé le message, prévoyez un mécanisme de réessai pour faire consommer à nouveau le message. Les échecs des messages de consommation par les consommateurs peuvent généralement être pris en compte dans les situations suivantes :
- En raison de la raison du message lui-même, comme une défaillance de désérialisation, les données du message elles-mêmes ne peuvent pas être traitées (comme la recharge de la facture de téléphone, le numéro de téléphone mobile du message en cours est déconnecté, ne peut pas être rechargé), etc. Cette erreur nécessite généralement de sauter ce message et de consommer d’autres messages, et ce message échoué est à 99 % infructueux même si la consommation est retentée immédiatement, il est donc préférable de fournir un mécanisme de réessai chronométrée, c’est-à-dire de réessayer après 10 secondes.
- Parce que les services applicatifs dépendants en aval sont indisponibles, comme la connexion de la base de données indisponible, le réseau système externe inaccessible, etc. En cas de rencontre avec cette erreur, même si le message d’échec actuel est sauté, d’autres messages seront également consommés. Dans ce cas, il est recommandé d’appliquer des 30 heures de sommeil et de consommer le message suivant, ce qui peut réduire la pression sur le courtier pour réessayer le message.
Aperçu de RocketMQ Voyons si RocketMQ résout les problèmes rencontrés par le middleware de messages mentionné ci-dessus.
Qu’est-ce que RocketMQ ?
La figure ci-dessus est un modèle typique de middleware de messages envoyant et recevant des messages, RocketMQ est également conçu de cette manière, en résumé, RocketMQ possède les caractéristiques suivantes :
- Il s’agit d’un middleware de type file d’attente avec des performances élevées, une grande fiabilité, des caractéristiques en temps réel élevées et distribuées.
- Producteur, Consommateur et File d’attente peuvent tous être distribués.
- Le producteur envoie des messages à certaines files d’attente à tour de rôle, la collection de files d’attente s’appelle Topic, Consumer If broadcast consumption, une instance consommateur consomme toutes les files correspondant à ce sujet, et si c’est consommé par cluster, plusieurs instances consommateurs consomment la collection de files correspondant à ce sujet de manière égale.
- Un ordre strict des messages peut être garanti
- Fournit des modes de tir de messages enrichis
- Capacités efficaces d’extension horizontale des abonnés
- Mécanisme d’abonnement aux messages en temps réel
- Capacité d’accumulation de centaines de millions de messages
- Moins de dépendance
Structure de déploiement physique RocketMQ
Comme montré dans la figure ci-dessus, la structure de déploiement de RocketMQ présente les caractéristiques suivantes :
- Le Serveur de Noms est un nœud pratiquement sans état qui peut être déployé en cluster sans aucune synchronisation d’information entre les nœuds.
- Le déploiement de Broker est relativement complexe, Broker est divisé en Maître et Esclave, un Maître peut correspondre à plusieurs Esclaves, mais un Esclave ne peut correspondre qu’à un seul Maître, la correspondance entre Maître et Esclave est définie par la spécification du même Nom de Courtier, un BrokerId, un BrokerId est 0 pour Maître, et non-0 signifie Esclave. Les maîtres peuvent également être déployés en plusieurs formats. Chaque courtier établit une longue connexion avec tous les nœuds du cluster de serveurs de noms et enregistre les informations de sujet à tous les serveurs de noms à intervalles réguliers.
- Le producteur établit une longue connexion avec l’un des nœuds du cluster de Serveurs de Noms (sélectionné aléatoirement), récupère périodiquement les informations de routage des sujets depuis le serveur de noms, établit une longue connexion avec le maître qui fournit le service de sujet, et envoie des battements de cœur au maître à intervalles réguliers. Producer est complètement sans état et peut être déployé en clusters.
- Le consommateur établit une longue connexion avec l’un des nœuds du cluster du serveur de noms (sélectionné aléatoirement), récupère régulièrement les informations de routage des sujets auprès du serveur de noms, établit une longue connexion avec le Maître et l’Esclave qui fournissent le service de sujet, et envoie des battements de cœur au Maître et à l’Esclave à intervalles réguliers. Les consommateurs peuvent s’abonner aux messages du Maître et de l’Esclave, et les règles d’abonnement sont déterminées par la configuration du Courtier.
Structure de déploiement logique RocketMQ
Comme montré dans la figure ci-dessus, la structure logique de déploiement de RocketMQ présente deux caractéristiques : productrice et consommateur.
Utilisé pour représenter une application de messagerie, un Groupe de Producteurs contient plusieurs instances de Producteurs, qui peuvent être plusieurs machines, plusieurs processus d’une machine ou plusieurs objets Producteurs d’un processus. Un groupe de producteurs peut envoyer plusieurs messages de sujet, et le groupe de producteurs fonctionne comme suit :
- Identifiez un type de producteur
- Vous pouvez vérifier qu’il existe plusieurs instances de Producer dans cette application de messagerie via l’outil O&M
- Lors de l’envoi d’un message de transaction distribuée, si le producteur tombe en panne de façon inattendue, le courtier rappellera activement n’importe quelle machine du groupe de producteurs pour confirmer le statut de la transaction.
Utilisé pour représenter une application de messagerie grand public, un groupe de consommateurs contient plusieurs instances de consommateurs, qui peuvent être plusieurs machines, plusieurs processus ou plusieurs objets consommateurs d’un processus. Plusieurs consommateurs dans un groupe de consommateurs consomment les messages de manière uniformément répartie, et si elles sont configurées sur diffusion, chaque instance sous ce groupe consomme la totalité des données.
Structure de stockage des données RocketMQ
Comme montré dans la figure ci-dessus, RocketMQ adopte une méthode de stockage qui sépare les données des index. Réduire efficacement la perte de ressources de fichiers, d’entrées / sorties et de mémoire. Même avec des données massives comme Alibaba, des scénarios de forte concurrence peuvent efficacement réduire la latence de bout en bout et offrir de fortes capacités d’échelle horizontale.
|