RabbitMQ vs Kafka

Les deux acheminent des messages, mais le modèle diffère. RabbitMQ = file d'attente : un message consommé est enlevé de la file, idéal pour distribuer des tâches entre workers (« qui prend celui-là ? »). Kafka = journal persistant : les messages restent et peuvent être rejoués par plusieurs consommateurs indépendants. Pour un projet Python qui veut décharger des tâches asynchrones avec Celery, RabbitMQ ou Redis sont les choix naturels.

À quoi ça sert

Ton API reçoit une requête qui demande de générer un PDF, d'envoyer un e-mail, ou de lancer une prédiction lourde. Tu ne veux pas que l'utilisateur attende la fin du travail. Solution : tu déposes un « ticket » dans une file, ton API répond {"status":"queued"}, et un worker en arrière-plan prend les tickets un par un et les traite.

RabbitMQ est ce qui s'occupe de la file. Trois concepts à retenir :

  • Queue — la file d'attente. Les messages s'accumulent ici en attendant d'être consommés.
  • Exchange — l'aiguilleur. Les producteurs publient toujours sur un exchange, qui décide vers quelle(s) queue(s) router le message selon des règles (clé de routage, type d'exchange).
  • Binding — la règle qui relie un exchange à une queue.

Le tout avec acquittement : un message n'est retiré que si le worker confirme qu'il l'a traité. Si le worker crashe avant de confirmer, RabbitMQ redonne le message à un autre worker. Tu ne perds rien.

En une phrase

RabbitMQ = la poste fiable qui prend tes messages, les range dans la bonne boîte, et garantit qu'ils seront livrés à un destinataire — quitte à réessayer.

Un exemple d'usage

Une route FastAPI déclenche l'envoi d'un e-mail de bienvenue. On veut que l'API rende la main tout de suite et qu'un worker à part s'occupe de parler au serveur SMTP (qui est lent et peut planter).

python (producer côté API)
import pika, json

connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
channel.queue_declare(queue="emails", durable=True)

channel.basic_publish(
    exchange="",
    routing_key="emails",
    body=json.dumps({"to": "a@b.fr", "subject": "Bienvenue"}),
    properties=pika.BasicProperties(delivery_mode=2),  # persistant
)
python (worker)
import pika, json

connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
channel = connection.channel()
channel.queue_declare(queue="emails", durable=True)
channel.basic_qos(prefetch_count=1)

def handle(ch, method, props, body):
    job = json.loads(body)
    send_email(job["to"], job["subject"])
    ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(queue="emails", on_message_callback=handle)
channel.start_consuming()

Lance plusieurs workers : RabbitMQ distribue les messages en round-robin, débit ×N. En vrai, pour faire ça en Python on n'écrit presque jamais ce code à la main : on utilise Celery, qui s'occupe de tout.

How-to : démarrer avec RabbitMQ

  1. Lancer RabbitMQ avec Docker

    L'image officielle existe avec UI de management intégrée — c'est celle-là qu'on utilise pour apprendre :

    bash
    docker run -d --name rabbitmq \
      -p 5672:5672 -p 15672:15672 \
      -v rabbitmq-data:/var/lib/rabbitmq \
      rabbitmq:3-management
    • 5672 : port AMQP, utilisé par tes apps.
    • 15672 : UI web. Login par défaut : guest / guest.
  2. Découvrir l'UI de management

    http://localhost:15672. Onglets clés :

    • Queues — liste des files, taux de messages/s entrants et sortants, profondeur (combien attendent).
    • Exchanges — les aiguilleurs. Tu en as déjà quelques-uns par défaut (amq.direct, amq.fanout…).
    • Connections et Channels — qui parle au broker en ce moment.

    Tu peux publier un message à la main depuis l'UI — pratique pour tester un worker sans écrire un producer.

  3. Installer le client Python

    bash
    uv add pika

    pika est synchrone et simple à lire. Pour de l'async, regarde aio-pika.

  4. Comprendre les types d'exchanges

    • direct — route selon une routing key exacte. orders.created arrive dans la queue bindée sur orders.created.
    • fanout — diffuse à toutes les queues bindées (broadcast). Utile pour notifier plusieurs services simultanément.
    • topic — comme direct mais avec wildcards : orders.* attrape orders.created et orders.cancelled.
    • headers — route selon les en-têtes du message. Plus rare.

    Pour démarrer, l'exchange par défaut (vide) suffit : il route vers la queue dont le nom = la routing key. C'est ce qu'on voit dans l'exemple plus haut.

  5. Acks et durabilité

    Trois choses à activer ensemble pour ne rien perdre :

    1. Queue durable : queue_declare(queue=..., durable=True).
    2. Message persistant : delivery_mode=2 dans les properties.
    3. Ack manuel : le worker appelle basic_ack seulement après avoir réussi le travail. Si le worker crashe avant, RabbitMQ redélivre.

    basic_qos(prefetch_count=1) dit au broker de ne pas envoyer plus d'un message non-acké à la fois à ce worker — sinon un worker rapide accapare la file.

  6. Dead letter queue (DLQ)

    Pour les messages qui échouent en boucle (poison pills), configure la queue avec une dead-letter-exchange : après n tentatives ratées, le message est routé vers une file de quarantaine. Tu vas la voir et décider quoi en faire, plutôt que tourner en rond.

Aide-mémoire

CLI (rabbitmqctl, dans le conteneur)
rabbitmqctl list_queues name messages consumers
rabbitmqctl list_exchanges name type
rabbitmqctl list_bindings
rabbitmqctl add_user app monsecret
rabbitmqctl set_permissions -p / app ".*" ".*" ".*"
URL de connexion
# Format AMQP standard, accepté par pika, Celery, etc.
amqp://user:password@host:5672/vhost

# En local par défaut
amqp://guest:guest@localhost:5672/

RabbitMQ et le reste de l'écosystème

  • Celery — l'usage n°1 de RabbitMQ en Python. Tu écris des fonctions, Celery gère la sérialisation, les retries, les acks. Redis est l'autre broker possible (plus simple, moins de garanties).
  • Kafka — voir l'encart en haut : modèles différents, choisis selon ton besoin.
  • FastAPI — pattern classique : route → publication d'une tâche → réponse 202 Accepted. Le travail lourd se fait ailleurs.
  • Docker — l'image rabbitmq:3-management est l'installation type. Sur Kubernetes, l'opérateur officiel gère cluster, persistence et upgrades.
  • Prometheus + Grafana — RabbitMQ expose un endpoint /metrics Prometheus depuis sa version 3.8 (via plugin). Dashboard tout prêt sur grafana.com (id 10991).

Pour aller plus loin