Dépannage des performances RabbitMQ : lenteur et utilisation élevée du processeur
Diagnostiquez la lenteur et l'utilisation élevée du processeur de RabbitMQ en vérifiant les files d'attente, les consommateurs, le renouvellement des connexions, les entrées/sorties disque, le contrôle de flux et le comportement des clients.
Dépannage des performances RabbitMQ : lenteur et utilisation élevée du processeur
RabbitMQ est un courtier de messages robuste et largement adopté, mais comme tout système distribué, il peut subir une dégradation des performances, se manifestant souvent par une lenteur générale ou une utilisation excessive du processeur. Identifier la cause racine—qu'elle réside dans la configuration réseau, les entrées/sorties disque ou la logique applicative—est crucial pour maintenir la santé du système et une faible latence.
Ce guide sert de manuel pratique de dépannage pour diagnostiquer et résoudre les goulots d'étranglement de performance courants dans votre déploiement RabbitMQ. Nous examinerons les points de surveillance critiques et fournirons des mesures concrètes pour optimiser le débit et stabiliser la charge CPU, garantissant ainsi que votre courtier de messages fonctionne de manière fiable sous pression.
Triage initial : identifier le goulot d'étranglement
Avant de plonger dans des modifications de configuration approfondies, il est essentiel de déterminer où se situe le goulot d'étranglement. Une utilisation élevée du processeur ou une lenteur indique généralement l'un des trois domaines suivants : saturation du réseau, entrées/sorties disque intensives ou interactions applicatives inefficaces avec le courtier.
1. Surveillance de la santé de RabbitMQ
La première étape consiste à utiliser les outils de surveillance intégrés de RabbitMQ, principalement le Plugin de gestion.
Métriques clés à surveiller :
- Taux de messages : Recherchez des pics soudains dans les taux de publication ou de livraison qui dépassent la capacité soutenue du système.
- Longueurs des files d'attente : Des files d'attente qui croissent rapidement indiquent que les consommateurs sont en retard par rapport aux producteurs, ce qui entraîne souvent une pression accrue sur la mémoire/le disque.
- Activité des canaux/connexions : Un renouvellement élevé (ouverture et fermeture fréquentes des connexions/canaux) consomme des ressources CPU importantes.
- Alertes disque : Si l'utilisation du disque approche le seuil configuré, RabbitMQ ralentit délibérément la livraison des messages pour éviter la perte de données (contrôle de flux).
2. Inspection du système d'exploitation
RabbitMQ fonctionne sur la machine virtuelle Erlang, qui est sensible à la contention des ressources au niveau du système d'exploitation. Utilisez des outils standard pour confirmer la santé du système :
- Utilisation du processeur : Utilisez
topouhtop. Le processusrabbitmq-serverconsomme-t-il la majeure partie du processeur ? Si c'est le cas, examinez la répartition des processus Erlang (voir section ci-dessous). - Attente d'E/S : Utilisez
iostatouiotop. Des temps d'attente d'E/S élevés indiquent souvent des disques lents, surtout si la persistance est fortement utilisée. - Latence réseau : Utilisez
pingentre les producteurs, les consommateurs et les nœuds du courtier pour exclure une instabilité réseau générale.
Analyse approfondie : analyse de l'utilisation élevée du processeur
Une utilisation élevée du processeur dans RabbitMQ est souvent attribuée à des opérations intensives gérées par la machine virtuelle Erlang ou à une activité de protocole spécifique.
Comprendre la charge des processus Erlang
L'environnement d'exécution Erlang gère les processus efficacement, mais certaines tâches sont liées au processeur. Si l'utilisation du processeur du serveur RabbitMQ atteint 100 % sur tous les cœurs, examinez quel groupe de processus Erlang est responsable.
Gestionnaires de protocole (AMQP/MQTT/STOMP)
Si de nombreux clients établissent et démontent constamment des connexions ou publient d'énormes volumes de petits messages, le coût CPU de l'authentification, de la configuration des canaux et du traitement des paquets augmente considérablement. Le renouvellement fréquent des connexions est un tueur de processeur majeur.
Meilleure pratique : Privilégiez les connexions persistantes et de longue durée. Utilisez le regroupement de connexions côté client pour minimiser les frais généraux des phases de négociation et de configuration répétées.
Indexation des files d'attente et messages persistants
Lorsque les files d'attente sont fortement utilisées, en particulier lorsque les messages sont persistants (écrits sur le disque), la charge CPU peut augmenter en raison de :
- Gestion des entrées/sorties disque : Coordination des écritures sur disque et vidage des tampons.
- Indexation des messages : Suivi des emplacements des messages dans la structure de la file d'attente, en particulier dans les files d'attente hautement durables et à haut débit.
Limitation et contrôle de flux
RabbitMQ implémente un contrôle de flux pour se protéger lorsque les ressources sont limitées. Si un nœud atteint un seuil haut pour la mémoire ou l'espace disque, il applique une limitation interne, ce qui peut se manifester par une lenteur pour les producteurs.
Si vous voyez de nombreux messages bloqués en raison du contrôle de flux, la solution immédiate consiste à libérer des ressources (par exemple, assurez-vous que les consommateurs sont actifs ou augmentez l'espace disque). La solution à long terme consiste à mettre à l'échelle le cluster ou à optimiser le débit des consommateurs.
Dépannage des consommateurs lents et de l'accumulation de files d'attente
La lenteur est souvent perçue par la couche applicative lorsque les consommateurs ne peuvent pas suivre le rythme d'entrée. Il s'agit généralement d'un problème côté consommateur ou d'un problème réseau entre le consommateur et le courtier.
Stratégie d'accusé de réception du consommateur
La manière dont les consommateurs accusent réception des messages a un impact profond sur le débit et l'utilisation du processeur sur le courtier.
- Accusé de réception manuel (
manual ack) : Offre une fiabilité mais nécessite que le consommateur confirme la réception. Si le consommateur se bloque, RabbitMQ conserve le message, ce qui peut saturer la mémoire et entraîner des retards pour les autres messages de cette file d'attente. - Accusé de réception automatique (
auto ack) : Maximise le débit initialement, mais si le consommateur plante après avoir reçu un message mais avant de le traiter, le message est perdu définitivement.
Si vous utilisez des accusés de réception manuels et constatez des ralentissements, vérifiez le nombre de Messages non accusés dans le Plugin de gestion. Si ce nombre est élevé, les consommateurs sont soit lents, soit ne parviennent pas à accuser réception.
Optimisation du nombre de prélecture
Le paramètre qos (Qualité de service), en particulier le nombre de prélecture, détermine le nombre de messages qu'un consommateur peut détenir sans accusé de réception.
Si le nombre de prélecture est trop élevé (par exemple, 1000), un seul consommateur lent peut extraire un arriéré massif de la file d'attente, privant ainsi d'autres consommateurs potentiellement plus rapides sur la même file d'attente.
Exemple : Si un consommateur ne traite que 10 msg/s, définir prefetch_count à 100 est inutile et concentre la charge inutilement.
# Exemple de définition d'un nombre de prélecture raisonnable (par exemple, 50)
# Utilisation d'une bibliothèque cliente équivalente (représentation conceptuelle)
channel.basic_qos(prefetch_count=50)
Latence réseau entre le consommateur et le courtier
Si le consommateur est rapide mais met du temps à accuser réception des messages reçus sur le réseau, le problème est probablement la latence ou la saturation du réseau entre le consommateur et le nœud RabbitMQ auquel il est connecté.
- Test : Connectez temporairement le consommateur au courtier sur la même machine (localhost) pour éliminer les variables réseau. Si les performances s'améliorent considérablement, concentrez-vous sur l'optimisation du réseau (par exemple, cartes réseau dédiées, vérification des pare-feu intermédiaires).
Impact des entrées/sorties disque et de la persistance
Les performances du disque sont souvent le plafond dur des performances, en particulier pour les files d'attente utilisant une haute durabilité.
Messages persistants et durabilité
- Échanges et files d'attente durables : Essentiels pour éviter les pertes lors du redémarrage du courtier, mais ils entraînent des frais généraux de métadonnées.
- Messages persistants : Les messages marqués comme persistants doivent être écrits sur le disque avant que le courtier n'envoie un accusé de réception au producteur. Des disques lents se traduisent directement par un débit de production lent.
Si votre charge est principalement composée de messages transitoires (non persistants), assurez-vous que la file d'attente elle-même n'est pas durable, ou, plus pratiquement, marquez les messages comme transitoires si la perte de données est acceptable pour cette charge utile spécifique. Les messages transitoires sont beaucoup plus rapides car ils restent en RAM (sous réserve de pression mémoire).
Frais généraux de mise en miroir
Dans un cluster haute disponibilité (HA), la mise en miroir des files d'attente réplique les données sur plusieurs nœuds. Bien qu'essentielle pour la tolérance aux pannes, la mise en miroir ajoute une charge d'écriture importante au cluster. Si la latence du disque est élevée, cette charge peut saturer la capacité d'E/S, ralentissant toutes les opérations.
Conseil d'optimisation : Pour les files d'attente qui nécessitent un débit d'écriture élevé mais peuvent tolérer une perte de données mineure lors d'un basculement (par exemple, les flux de journalisation), envisagez d'utiliser des files d'attente non mises en miroir sur un ensemble de nœuds hautement disponibles, ou utilisez des Files d'attente paresseuses si la longueur de la file d'attente devrait devenir extrêmement grande (les files d'attente paresseuses déplacent les messages non consommés sur le disque plus tôt pour économiser la RAM).
Distinguer les problèmes du courtier des problèmes applicatifs
RabbitMQ est souvent blâmé pour une latence qui commence ailleurs. Une requête web expire, un travail se termine en retard ou une base de données en aval est lente, et la file d'attente est la chose la plus facile à remarquer car sa profondeur est visible. Avant de régler le courtier, décidez si RabbitMQ est lent ou si RabbitMQ vous montre que les consommateurs sont lents.
Commencez par trois nombres pour la file d'attente concernée :
rabbitmqctl list_queues name messages_ready messages_unacknowledged consumers \
message_stats.publish_details.rate message_stats.deliver_get_details.rate \
message_stats.ack_details.rate
Si messages_ready augmente alors que des consommateurs sont présents et que les accusés de réception sont lents, les consommateurs ne suivent pas. Le courtier est peut-être en bonne santé. Si messages_unacknowledged augmente, les consommateurs reçoivent des messages mais ne les terminent pas ou ne les accusent pas. Si les confirmations de publication deviennent lentes alors que des alertes de disque ou de mémoire sont actives, le courtier applique une contre-pression. Si le processeur est élevé et que le nombre de connexions augmente, le comportement du client peut en être la cause.
Cette distinction est importante car ajouter de la RAM à RabbitMQ ne résoudra pas un consommateur qui passe deux secondes à appeler une API lente pour chaque message. Augmenter les répliques de consommateurs ne résoudra pas un courtier limité par les écritures disque. Modifier la prélecture ne résoudra pas un producteur qui ouvre une nouvelle connexion TCP pour chaque publication.
Renouvellement des connexions et des canaux
Une utilisation élevée du processeur par RabbitMQ est souvent banale : trop de clients ouvrent et ferment des connexions de manière répétée. La configuration d'une connexion AMQP n'est pas gratuite. Elle comprend la configuration TCP, la négociation TLS facultative, l'authentification, le réglage et la négociation des canaux. Si une application ouvre une connexion pour chaque message, chaque requête HTTP ou chaque travail court, RabbitMQ dépense du processeur pour le travail de configuration au lieu de déplacer des messages.
Examinez l'âge et le nombre de connexions :
rabbitmqctl list_connections name user peer_host state channels connected_at
rabbitmqctl list_channels connection number user vhost
Si vous voyez un flux constant de connexions de courte durée provenant du même service, corrigez le client. Gardez les connexions de longue durée. Utilisez les canaux de manière appropriée. La plupart des services devraient créer une connexion au démarrage et la réutiliser jusqu'à l'arrêt, avec une logique de reconnexion en cas d'échec. Dans les applications web, ne créez pas de connexion au courtier à l'intérieur du gestionnaire de requêtes, sauf si votre framework dispose d'un pool de connexions très délibéré.
TLS rend le renouvellement plus coûteux. TLS est acceptable pour la production, mais les négociations répétées peuvent devenir visibles sous charge. La réutilisation des connexions reste la solution.
Prélecture adaptée au travail
La prélecture n'est pas un bouton magique de débit. Elle contrôle le nombre de messages non accusés qu'un consommateur peut détenir. La bonne valeur dépend du temps de traitement, de la taille des messages et de l'équité entre les consommateurs.
Une prélecture de 1 est simple et équitable, mais elle peut sous-utiliser les consommateurs lorsque chaque travail comporte de petites attentes pour le réseau ou le disque. Une prélecture de 500 peut sembler rapide dans un benchmark, mais un consommateur lent peut accaparer le travail et augmenter les problèmes de redistribution lorsqu'il plante.
Un point de départ pratique consiste à mesurer le temps qu'un consommateur passe par message. Si le travail est intensif en CPU et que chaque processus gère un message à la fois, gardez la prélecture basse. Si le travail attend un service distant et que le consommateur gère la concurrence en interne, une prélecture modérée peut le maintenir occupé. Augmentez par étapes et surveillez :
- le taux d'accusés de réception ;
messages_unacknowledged;- la mémoire du consommateur ;
- la latence de bout en bout ;
- le nombre de redistributions après un redémarrage du consommateur.
Le test doit inclure une panne. Tuez un consommateur pendant qu'il détient des messages non accusés. Si la redistribution provoque une énorme rafale de travail en double ou de longs blocages, la prélecture est probablement trop élevée pour cette file d'attente.
Messages persistants et réalité du disque
Les messages persistants et les files d'attente durables sont le bon choix pour un travail important, mais ils déplacent une partie du goulot d'étranglement vers le stockage. Lorsque les éditeurs attendent des confirmations, les écritures disque lentes se manifestent par des publications lentes. Lorsque les files d'attente deviennent grandes, RabbitMQ a plus de travail d'indexation et de stockage à effectuer. Dans les configurations en cluster, la réplication ajoute également du travail réseau et disque.
Vérifiez les symptômes du disque à partir du système d'exploitation :
iostat -xz 1
vmstat 1
Une attente d'E/S élevée, une utilisation élevée du disque ou des temps d'attente longs vous indiquent que le courtier attend le stockage. Cela ne signifie pas "désactiver la persistance". Cela signifie que vous avez besoin d'un stockage plus rapide, de moins de messages persistants inutiles, d'un taux de publication plus faible, d'un regroupement plus efficace ou d'une topologie qui répartit le travail sur plusieurs nœuds.
Évitez de placer les répertoires de données RabbitMQ sur des disques réseau lents, sauf si vous avez testé la configuration exacte. RabbitMQ se soucie autant de la latence que du débit. Un disque qui semble acceptable pour les copies de fichiers en masse peut encore être médiocre pour les charges de travail de messages.
Type de file d'attente et choix de réplication
Les anciens conseils RabbitMQ mentionnent souvent les files d'attente classiques mises en miroir. Dans les déploiements RabbitMQ actuels, les files d'attente de quorum sont généralement préférées pour les charges de travail durables répliquées, tandis que les files d'attente classiques conviennent toujours à de nombreux cas moins critiques ou non répliqués. Le meilleur choix dépend de la version de RabbitMQ, des exigences opérationnelles et de la charge de travail.
Les files d'attente de quorum améliorent le modèle de défaillance pour les files d'attente durables répliquées, mais elles ne sont pas gratuites. Elles se répliquent via un protocole de consensus, donc les écritures impliquent plusieurs nœuds. Si vous placez chaque flux d'événements transitoires à volume élevé dans des files d'attente de quorum, vous pouvez créer un problème de performance dont vous n'aviez pas besoin.
Utilisez une durabilité plus forte là où elle correspond à la valeur commerciale :
- les flux de paiement, de commande, d'inventaire et d'audit méritent souvent des files d'attente durables répliquées ;
- l'actualisation du cache, les métriques et les notifications reconstructibles peuvent ne pas nécessiter la même protection ;
- les très grands arriérés peuvent nécessiter une révision de conception plutôt qu'un simple courtier plus gros.
Le but n'est pas de minimiser la sécurité. Il s'agit d'éviter de payer le coût de fiabilité le plus élevé pour des données qui peuvent être recréées, tout en protégeant les messages qui ne le peuvent pas.
Les gros messages compliquent tout
RabbitMQ peut transporter de gros messages, mais les files d'attente sont généralement plus saines lorsque les messages sont petits. Un message contenant une grande image, un rapport, une archive ou une exportation complète de base de données augmente la pression mémoire, la pression disque, le temps de transfert réseau et le coût de redistribution.
Pour les charges utiles volumineuses, stockez la charge utile dans un stockage d'objets ou une base de données et envoyez un message contenant une référence :
{
"job_id": "report-2026-05-25-001",
"object_url": "s3://reports-bucket/report-2026-05-25-001.json",
"sha256": "..."
}
Le consommateur récupère la charge utile lorsqu'il est prêt à la traiter. Cette conception n'est pas parfaite ; vous avez maintenant besoin d'un nettoyage du cycle de vie et d'un contrôle d'accès pour le magasin de charges utiles. Mais elle maintient RabbitMQ concentré sur la coordination au lieu de devenir un système de transport de fichiers.
Lorsque le processeur est élevé mais que les files d'attente sont vides
Des files d'attente vides ne signifient pas toujours que RabbitMQ est inactif. Le processeur peut être élevé parce que les clients se connectent constamment, s'authentifient, publient des messages non routables, déclarent la topologie ou sondent avec des modèles inefficaces.
Vérifiez l'interface utilisateur de gestion ou la CLI pour le renouvellement des connexions et le nombre de canaux. Examinez les journaux d'application pour les boucles de reconnexion. Recherchez les clients qui déclarent des échanges et des files d'attente avant chaque publication. La déclaration de topologie est généralement idempotente, mais le faire à très haute fréquence ajoute toujours du travail au courtier.
Vérifiez également les plugins. La gestion, la fédération, la pelle, MQTT, STOMP, le traçage et les plugins personnalisés ajoutent tous du travail lorsqu'ils sont activés et utilisés. Ne désactivez pas un plugin aveuglément lors d'un incident, mais confirmez si la charge correspond à l'activité du plugin.
Une routine de réglage plus sûre
Modifiez une chose à la fois et enregistrez les chiffres avant/après. Le travail de performance RabbitMQ devient confus lorsque la prélecture, le nombre de consommateurs, le type de file d'attente, la persistance et le matériel changent tous dans le même déploiement.
Une routine utile :
- Capturez les taux de file d'attente, la profondeur de la file d'attente, les messages non accusés, le nombre de connexions, le processeur, la mémoire, les entrées/sorties disque et la latence de confirmation de publication.
- Choisissez le goulot d'étranglement probable.
- Effectuez une modification.
- Exécutez la même charge de travail.
- Comparez la latence de bout en bout, pas seulement le débit du courtier.
Si l'incident est actif, choisissez d'abord des modifications réversibles : ajoutez des consommateurs, arrêtez le renouvellement des connexions, réduisez le taux de production, videz un arriéré ou déplacez les charges de travail optionnelles. Réservez les migrations de type de file d'attente et les refontes de stockage pour un travail planifié, sauf si le système est déjà en panne et que vous n'avez pas de chemin plus sûr.
Résumé des mesures concrètes
Face à une utilisation élevée du processeur ou à une lenteur généralisée, suivez cette liste de contrôle :
- Vérifiez les alertes : Assurez-vous qu'aucune alerte de contrôle de flux de disque ou de mémoire n'est active.
- Inspectez le comportement du client : Recherchez un renouvellement élevé des connexions/canaux ou des clients utilisant
auto-ackde manière inappropriée. - Optimisez les consommateurs : Ajustez
prefetch_countpour correspondre à la vitesse de traitement réelle de vos consommateurs. - Vérifiez la vitesse du disque : Assurez-vous que le backend de stockage est suffisamment rapide pour vos besoins de persistance et de réplication.
- Profilez Erlang (avancé) : Utilisez les outils Erlang (par exemple,
observer) pour confirmer si le processeur est dépensé pour la gestion du protocole par rapport à la gestion interne des files d'attente.
En analysant systématiquement l'utilisation des ressources au niveau du système d'exploitation, du courtier et de l'application, vous pouvez isoler et éliminer efficacement les causes profondes des problèmes de performance de RabbitMQ.