Kafka vs RabbitMQ — lequel choisir ?

Les deux font transiter des messages entre services, mais le modèle est différent. RabbitMQ = une poste : un message consommé est enlevé de la file. Kafka = un journal : les messages restent sur disque, plusieurs consommateurs peuvent rejouer le même flux à leur rythme. Choisis Kafka pour des flux massifs et de l'analytique, RabbitMQ pour de la distribution de tâches précise entre services.

À quoi ça sert

Imagine que ton site e-commerce génère un événement à chaque clic, chaque ajout au panier, chaque commande. Plusieurs équipes en ont besoin : la facturation, les stats, la recommandation, l'envoi d'e-mails. Sans Kafka, chaque service appellerait chaque autre — et au bout d'un moment c'est l'enfer (graphe d'appels, latences, indispos en cascade).

Kafka inverse le modèle :

  • Topics — des « canaux » nommés (par ex. orders, clicks) où on dépose des événements.
  • Producers — n'importe quel service publie dans un topic, sans savoir qui lira.
  • Consumers — chaque service qui s'intéresse à un topic s'abonne et lit à son rythme. Plusieurs consommateurs indépendants peuvent lire le même topic.
  • Persistance — les événements restent sur disque (par défaut 7 jours, configurable). On peut rejouer l'historique — utile pour réindexer ou entraîner un modèle.
  • Partitions — chaque topic est découpé en partitions réparties sur plusieurs brokers (les serveurs Kafka). C'est ce qui permet de scaler à des millions de messages par seconde.
En une phrase

Kafka = un journal partagé, durable et ultra-rapide, où chaque équipe écrit ce qui se passe et où chaque autre équipe vient se servir.

Un exemple d'usage

Tu collectes les prédictions de ton modèle de classification d'images pour les analyser plus tard (et éventuellement réentraîner). Côté API, après chaque prédiction, tu publies un événement dans un topic predictions :

python (producer)
from kafka import KafkaProducer
import json

producer = KafkaProducer(
    bootstrap_servers="localhost:9092",
    value_serializer=lambda v: json.dumps(v).encode(),
)

producer.send("predictions", {
    "model": "v3",
    "input": "img_42.png",
    "label": "chat",
    "score": 0.94,
})
producer.flush()

De l'autre côté, un consommateur lit le flux pour archiver ou agréger :

python (consumer)
from kafka import KafkaConsumer
import json

consumer = KafkaConsumer(
    "predictions",
    bootstrap_servers="localhost:9092",
    group_id="archiver",
    value_deserializer=lambda v: json.loads(v),
)

for msg in consumer:
    print(msg.value)  # {"model":"v3", ...}

Demain, tu ajoutes un deuxième consommateur (groupe monitoring) qui lit le même topic pour calculer la distribution des classes. Aucun changement côté producer.

How-to : démarrer avec Kafka

  1. Lancer Kafka avec Docker

    Les versions récentes (Kafka 3.x+) tournent sans ZooKeeper, en mode KRaft. L'image officielle Bitnami est la plus simple à mettre en place :

    yaml
    # docker-compose.yml — Kafka mono-broker
    services:
      kafka:
        image: bitnami/kafka:3.7
        ports: ["9092:9092"]
        environment:
          KAFKA_CFG_NODE_ID: "0"
          KAFKA_CFG_PROCESS_ROLES: "controller,broker"
          KAFKA_CFG_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093"
          KAFKA_CFG_ADVERTISED_LISTENERS: "PLAINTEXT://localhost:9092"
          KAFKA_CFG_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
          KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: "0@kafka:9093"
        volumes:
          - kafka-data:/bitnami/kafka
    
    volumes:
      kafka-data:

    docker compose up -d. En prod on ne tourne jamais sur un seul broker — vise au minimum 3 pour la réplication, mais pour apprendre c'est largement suffisant.

  2. Créer un topic

    bash
    docker exec -it $(docker ps -qf name=kafka) \
      kafka-topics.sh --create \
      --topic predictions \
      --partitions 3 --replication-factor 1 \
      --bootstrap-server localhost:9092

    Partitions : plus tu en as, plus tu pourras avoir de consommateurs en parallèle dans un même groupe (chaque consommateur lit ≥ 1 partition). 3 est un bon point de départ.

  3. Installer le client Python

    bash
    uv add kafka-python

    Pour la production, regarde aussi confluent-kafka (binding du client C, plus rapide) ou aiokafka (async).

  4. Producer + Consumer côte à côte

    Lance le producer dans un terminal, le consumer dans un autre, puis envoie quelques messages. Tu vois apparaître les événements chez le consommateur en quasi-temps réel. Coupe le consommateur, envoie 10 messages, relance le consommateur : il reprend à partir du dernier offset commité (pas perdu).

  5. Comprendre les groupes de consommateurs

    Tous les consommateurs avec le même group_id forment un groupe : Kafka leur distribue les partitions. Avec 3 partitions et 3 consommateurs dans group=archiver, chacun en lit une — débit ×3. Si un 4ᵉ consommateur arrive, il reste oisif (il n'y a que 3 partitions). Si un consommateur tombe, ses partitions sont redistribuées automatiquement (rebalance).

    Deux groupes différents sur le même topic lisent le flux indépendamment, du début. C'est l'idée clé : plusieurs audiences pour un même flux.

  6. Inspecter avec une UI

    La CLI marche mais une UI aide énormément. Kafka UI (provectus) est la plus simple :

    yaml
    kafka-ui:
      image: provectuslabs/kafka-ui:latest
      ports: ["8080:8080"]
      environment:
        KAFKA_CLUSTERS_0_NAME: local
        KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092
      depends_on: [kafka]

    Ouvre http://localhost:8080 : tu vois les topics, partitions, messages, et les groupes de consommateurs avec leur lag (retard en messages).

Aide-mémoire

CLI (dans le conteneur Kafka)
kafka-topics.sh --bootstrap-server localhost:9092 --list
kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic predictions
kafka-console-producer.sh --bootstrap-server localhost:9092 --topic predictions
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic predictions --from-beginning
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --list
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group archiver --describe
vocabulaire
broker        # un serveur Kafka
topic         # un canal nommé
partition     # sous-division d'un topic, ordonnée
offset        # position dans une partition
producer      # publie
consumer      # lit
consumer group# ensemble de consumers qui se partagent les partitions
lag           # retard d'un groupe par rapport à la fin du topic

Kafka et le reste de l'écosystème

  • RabbitMQ — alternative plus légère pour de la distribution de tâches précises. Voir l'encart en haut.
  • Docker — quasi tous les labs Kafka commencent en Docker. En prod, on déploie sur Kubernetes via l'opérateur Strimzi.
  • FastAPI — une route qui, à la place de faire le travail, publie un événement Kafka et répond immédiatement. Un consommateur en arrière-plan fait le boulot lourd.
  • Prometheus + Grafana — Kafka expose ses métriques via JMX → exporter Prometheus. Un dashboard Grafana montre en direct le débit, le lag par groupe, etc.
  • MLflow — pour entraîner un modèle sur les événements passés, on rejoue un topic depuis l'offset 0 vers un job d'entraînement qui logge le résultat dans MLflow.

Pour aller plus loin