RabbitMQ Cluster¶
Introduction¶
RabbitMQ est le message broker central d'OpenStack. En mode cluster avec queues mirrorées (ou quorum queues), il assure la haute disponibilité de la messagerie asynchrone entre services.
Prérequis¶
- Concepts HA
- Compréhension du protocole AMQP
- Cluster de 3 controllers minimum
Points à apprendre¶
Architecture RabbitMQ HA¶
graph TB
nova["Nova Services<br/>Conductor, Scheduler<br/>Compute agents"]
neutron["Neutron Services<br/>Server, L3 Agent<br/>OVS Agent"]
cinder["Cinder Services<br/>Scheduler<br/>Volume"]
subgraph cluster["RabbitMQ Cluster"]
node1["RabbitMQ Node 1<br/>Controller-1<br/>Disk node<br/>Queues mirrored"]
node2["RabbitMQ Node 2<br/>Controller-2<br/>Disk node<br/>Queues mirrored"]
node3["RabbitMQ Node 3<br/>Controller-3<br/>Disk node<br/>Queues mirrored"]
end
nova -->|"AMQP<br/>5672"| node1
nova -.->|Failover| node2
neutron -->|"AMQP<br/>5672"| node2
cinder -->|"AMQP<br/>5672"| node3
node1 <-->|"Erlang<br/>Distribution<br/>25672"| node2
node2 <--> node3
node3 <--> node1
Types de réplication¶
graph TB
subgraph classic["Classic Mirrored Queues (Legacy)"]
m1["Master Queue<br/>(Node 1)"]
mi1["Mirror 1<br/>(Node 2)"]
mi2["Mirror 2<br/>(Node 3)"]
m1 -->|Sync| mi1
m1 -->|Sync| mi2
end
subgraph quorum["Quorum Queues (Recommandé)"]
l1["Leader<br/>(Node 1)"]
f1["Follower 1<br/>(Node 2)"]
f2["Follower 2<br/>(Node 3)"]
l1 -->|Raft| f1
l1 -->|Raft| f2
end
classic -.->|"Problèmes:<br/>- Split-brain possible<br/>- Synchronisation lente"| classic
quorum -.->|"Avantages:<br/>- Consensus Raft<br/>- Pas de split-brain<br/>- Plus performant"| quorum
Configuration Kolla¶
# /etc/kolla/globals.yml
enable_rabbitmq: "yes"
# Kolla configure automatiquement le cluster
# basé sur les hosts dans le groupe [rabbitmq]
# Pour les quorum queues (OpenStack Yoga+)
# rabbitmq_enable_quorum_queues: "yes"
Configuration RabbitMQ générée¶
# /etc/rabbitmq/rabbitmq.conf
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
cluster_formation.classic_config.nodes.1 = rabbit@controller-1
cluster_formation.classic_config.nodes.2 = rabbit@controller-2
cluster_formation.classic_config.nodes.3 = rabbit@controller-3
# Clustering
cluster_partition_handling = pause_minority
# HA Policy (mirrored queues)
# Appliquée via rabbitmqctl
# Networking
listeners.tcp.default = 5672
management.listener.port = 15672
# Erlang cookie pour l'authentification cluster
# Stocké dans /var/lib/rabbitmq/.erlang.cookie
Politique HA pour les queues¶
# Voir les policies actuelles
docker exec rabbitmq rabbitmqctl list_policies
# Kolla applique automatiquement cette policy:
docker exec rabbitmq rabbitmqctl set_policy ha-all ".*" \
'{"ha-mode":"all","ha-sync-mode":"automatic"}' \
--priority 0 \
--apply-to queues
# Pour quorum queues (plus performant):
docker exec rabbitmq rabbitmqctl set_policy ha-all ".*" \
'{"queue-type":"quorum"}' \
--priority 0 \
--apply-to queues
Monitoring du cluster¶
#!/bin/bash
# rabbitmq-status.sh
echo "=== Cluster Status ==="
docker exec rabbitmq rabbitmqctl cluster_status
echo -e "\n=== Node Health ==="
docker exec rabbitmq rabbitmq-diagnostics status
echo -e "\n=== Queue Status ==="
docker exec rabbitmq rabbitmqctl list_queues name messages consumers state
echo -e "\n=== Connections ==="
docker exec rabbitmq rabbitmqctl list_connections user client_properties state
echo -e "\n=== Memory Usage ==="
docker exec rabbitmq rabbitmqctl status | grep -A5 "Memory"
Gestion des partitions¶
# Stratégies de gestion des partitions (cluster_partition_handling):
# 1. pause_minority (recommandé pour OpenStack)
# - Les nœuds en minorité se mettent en pause
# - Évite le split-brain
# 2. pause_if_all_down
# - Pause si tous les autres nœuds sont down
# 3. autoheal
# - Redémarre automatiquement les nœuds après partition
# - Peut perdre des messages
# Vérifier s'il y a une partition
docker exec rabbitmq rabbitmqctl cluster_status | grep -A5 "Partitions"
Flux de messages¶
sequenceDiagram
participant API as Nova API
participant N1 as RabbitMQ<br/>Node 1 (Leader)
participant N2 as RabbitMQ<br/>Node 2 (Follower)
participant N3 as RabbitMQ<br/>Node 3 (Follower)
participant Conductor as Nova Conductor
API->>N1: Publish message<br/>(AMQP)
N1->>N1: Write to queue
alt Mirrored Queue
N1->>N2: Sync message
N1->>N3: Sync message
else Quorum Queue
N1->>N2: Raft append
N1->>N3: Raft append
N2-->>N1: ACK
N3-->>N1: ACK
N1->>N1: Commit (quorum atteint)
end
N1-->>API: ACK (confirmed)
Conductor->>N1: Consume message
N1-->>Conductor: Deliver message
Conductor->>N1: ACK (processed)
N1->>N1: Remove from queue
Note over N1,N3: Si Node 1 tombe:<br/>Node 2 devient leader<br/>Messages préservés
Récupération après panne¶
# Cas 1: Un nœud rejoint après redémarrage
docker exec rabbitmq rabbitmqctl cluster_status
# Le nœud doit apparaître dans "running_nodes"
# Cas 2: Nœud avec état incohérent
# Forcer le reset et rejoin
docker exec rabbitmq rabbitmqctl stop_app
docker exec rabbitmq rabbitmqctl reset
docker exec rabbitmq rabbitmqctl join_cluster rabbit@controller-1
docker exec rabbitmq rabbitmqctl start_app
# Cas 3: Forcer la synchronisation des queues
docker exec rabbitmq rabbitmqctl sync_queue <queue_name>
# Cas 4: Cluster complètement down
# Identifier le dernier nœud actif
docker exec rabbitmq rabbitmqctl force_boot
docker restart rabbitmq
Configuration HAProxy pour RabbitMQ¶
# HAProxy balance les connexions AMQP
listen rabbitmq_management
bind 10.0.0.10:15672
mode http
option httpchk GET /api/healthchecks/node
http-check expect status 200
server controller-1 10.0.0.11:15672 check inter 5s rise 2 fall 3
server controller-2 10.0.0.12:15672 check inter 5s rise 2 fall 3
server controller-3 10.0.0.13:15672 check inter 5s rise 2 fall 3
# Pour AMQP, connexion directe recommandée (pas de HAProxy)
# Les clients OpenStack utilisent transport_url avec tous les nœuds
Configuration OpenStack¶
# /etc/kolla/config/nova/nova.conf (et autres services)
[DEFAULT]
transport_url = rabbit://openstack:password@controller-1:5672,controller-2:5672,controller-3:5672//
# Retry settings
rabbit_retry_interval = 1
rabbit_retry_backoff = 2
rabbit_max_retries = 0
rabbit_durable_queues = true
rabbit_ha_queues = true
Exemples pratiques¶
Test de haute disponibilité¶
# Publier un message de test
docker exec rabbitmq rabbitmqadmin publish exchange=amq.default \
routing_key=test payload="test message"
# Arrêter un nœud
ssh controller-2 "docker stop rabbitmq"
# Vérifier le cluster (doit continuer à fonctionner)
docker exec rabbitmq rabbitmqctl cluster_status
# Vérifier que les queues sont toujours accessibles
docker exec rabbitmq rabbitmqctl list_queues
# Redémarrer le nœud
ssh controller-2 "docker start rabbitmq"
# Vérifier le rejoin
sleep 30
docker exec rabbitmq rabbitmqctl cluster_status
Monitoring avancé¶
# API Management (JSON)
curl -u guest:guest http://10.0.0.10:15672/api/overview | jq .
# Métriques pour Prometheus
curl http://10.0.0.10:15692/metrics
# Alertes sur les queues
docker exec rabbitmq rabbitmqctl list_queues name messages consumers | \
awk '$2 > 1000 {print "ALERT: Queue", $1, "has", $2, "messages"}'
Purge et maintenance¶
# Purger une queue (attention: perte de messages!)
docker exec rabbitmq rabbitmqctl purge_queue <queue_name>
# Supprimer une queue inutilisée
docker exec rabbitmq rabbitmqctl delete_queue <queue_name>
# Forcer la synchronisation de toutes les queues mirrorées
docker exec rabbitmq rabbitmqctl list_queues name slave_pids | \
while read name slaves; do
docker exec rabbitmq rabbitmqctl sync_queue "$name"
done
Ressources¶
Checkpoint¶
- Cluster RabbitMQ avec 3 nœuds fonctionnel
- Politique HA appliquée (ha-all ou quorum)
- Management UI accessible (port 15672)
- Failover testé (arrêt d'un nœud)
- Rejoin automatique après redémarrage
- Configuration transport_url avec tous les nœuds