🎯 OBJECTIF
Comprendre comment :
🧠 MODÈLE MENTAL
Tes pods et le cluster Kafka sont deux systèmes distincts avec des responsabilités séparées. Les pods traitent les messages, Kafka les stocke. Quand un pod crashe, Kafka fait un rebalance du consumer group. Quand un broker crashe, Kafka fait une élection de leader. Ces deux événements sont indépendants — scaler tes pods n'améliore pas la durabilité de Kafka.
La durabilité repose sur trois curseurs interdépendants : replication.factor (combien de copies), l'ISR (lesquelles sont à jour), et acks (combien doivent confirmer). Configurés séparément, chacun crée un faux sentiment de sécurité. Ensemble, ils définissent la garantie réelle. replication.factor=3 sans acks=all ni min.insync.replicas=2 ne protège de rien en cas de crash du leader.
acks=all.__cluster_metadata via l'algorithme Raft.flowchart LR
subgraph Pods["Pods Kubernetes (traitement)"]
P1["Pod A\nConsumer"]
P2["Pod B\nConsumer"]
P3["Pod C\nProducer"]
end
subgraph Kafka["Cluster Kafka (stockage)"]
B1["Broker 1\n(leader P0)"]
B2["Broker 2\n(leader P1)"]
B3["Broker 3\n(leader P2)"]
end
P1 --> B1
P2 --> B2
P3 --> B1
P3 --> B2mermaid| Brokers | Pods | |
|---|---|---|
| Rôle | Stocker les messages | Traiter les messages |
| Gèrent | Partitions, réplication, leaders | Logique métier, offsets |
| Crash | Leader election + failover | Rebalance consumer group |
| Durabilité | Dépend de replication.factor + acks |
Aucun impact sur la durabilité |
🔑 Conclusion clé
Scaler tes pods n'améliore pas la durabilité du cluster Kafka. La perte de données dépend uniquement de replication.factor, min.insync.replicas, acks, et de l'état de l'ISR au moment du crash.
Avec replication.factor=3, chaque partition a 1 leader et 2 followers sur des brokers différents.
sequenceDiagram
participant P as Producer
participant L as Leader (Broker 1)
participant F1 as Follower (Broker 2)
participant F2 as Follower (Broker 3)
P->>L: send(message)
L->>L: écrit dans son log local
L->>F1: push réplication
L->>F2: push réplication
F1-->>L: ack
F2-->>L: ack
L-->>P: confirmation (selon acks)mermaidLes followers ne vont pas chercher les données — c'est le leader qui pousse activement. Si un follower est lent ou déconnecté, le leader le détecte rapidement (pas de fetch entrant) et le retire de l'ISR.
L'ISR est la liste des replicas que Kafka considère suffisamment synchronisées pour valider une écriture. Une replica reste dans l'ISR si elle est vivante, réplique activement, et son retard ne dépasse pas replica.lag.time.max.ms (défaut : 30s).
Les trois curseurs fonctionnent ensemble — séparément, chacun crée un faux sentiment de sécurité :
replication.factor = 3 → combien de copies existent
min.insync.replicas = 2 → combien de copies synchronisées sont requises (avec acks=all)
acks = all → le producer attend la confirmation de toutes les replicas ISR
| Situation | ISR | Résultat avec min.insync.replicas=2 |
|---|---|---|
| Tout normal | [leader, f1, f2] | ✅ écriture acceptée |
| 1 broker down | [leader, f1] | ✅ 2 ≥ 2, acceptée |
| 2 brokers down | [leader] | ❌ 1 < 2, refusée — erreur explicite |
🚨 acks=all sans min.insync.replicas=2 = fausse sécurité
Avec min.insync.replicas=1 (défaut), l'ISR peut tomber à 1 seule replica sans que Kafka refuse l'écriture. Si ce leader unique crashe ensuite, les messages non répliqués sont perdus — malgré acks=all et replication.factor=3.
Config recommandée prod :
replication.factor = 3
min.insync.replicas = 2
acks = all
ZooKeeper était un service externe qui stockait toutes les métadonnées du cluster. Un seul controller Kafka était élu via ZooKeeper. En pratique : deux clusters à opérer, coordination externe, redémarrage lent sur gros clusters.
flowchart LR
subgraph Controllers["Quorum de controllers (3)"]
C1["Controller 1\n(leader actif)"]
C2["Controller 2\n(follower)"]
C3["Controller 3\n(follower)"]
end
subgraph Brokers["Brokers"]
B1["Broker 4"]
B2["Broker 5"]
B3["Broker 6"]
end
C1 -- "métadonnées\n__cluster_metadata" --> B1
C1 --> B2
C1 --> B3mermaid| ZooKeeper | KRaft | |
|---|---|---|
| Stockage métadonnées | Service externe | __cluster_metadata |
| Élection controller | Via ZooKeeper | Algorithme Raft |
| Clusters à maintenir | 2 (Kafka + ZK) | 1 (Kafka seul) |
| Redémarrage cluster | Lent (rechargement ZK) | Rapide (log local) |
🚨 Perte de quorum KRaft = cluster figé
Si 2 controllers sur 3 tombent simultanément (maintenance mal planifiée, crash en cascade), le quorum est perdu. Les brokers peuvent encore lire et écrire sur les topics existants, mais toute opération de gestion est bloquée : créer un topic, élire un nouveau leader si un broker tombe. Le cluster est fonctionnel mais ingérable.
Broker 2 : disque plein → ne peut plus écrire
↓
ISR rétrécit : [leader, f1, f2] → [leader, f1]
↓
UnderReplicatedPartitions > 0 (alerte critique)
↓
Si ISR size < min.insync.replicas → Kafka refuse les écritures
Un Full GC de 30s sur un broker entraîne un faux crash : le controller détecte le timeout de heartbeat, élit un nouveau leader, puis le broker revient — mais il n'est plus leader. Pic de latence, rebalance des consumers, surcharge des autres brokers. Difficile à distinguer d'un vrai crash sans monitoring fin.
UnderReplicatedPartitions > 0 est le signal d'alerte critique à monitorer en priorité. En temps normal, on tolère la perte d'un broker. En état sous-répliqué, on ne tolère plus rien :
replication.factor = 3, ISR normal : [Broker1, Broker2, Broker3]
Broker3 lent → ISR : [Broker1, Broker2] ← cluster fragilisé
Broker1 crash maintenant :
ISR : [Broker2] ← un seul broker, aucune redondance
Broker2 crash → partition totalement indisponible
⚡ TL;DR — chaque concept en une ligne
replication.factor
✓ Nombre total de copies d'une partition — détermine la tolérance aux pannes de brokers.
⚠ replication.factor=1 = zéro tolérance aux pannes sur les données, même avec KRaft.
ISR
✓ Liste des replicas à jour qui valident les écritures — l'indicateur de santé réel du cluster.
⚠ L'ISR peut se réduire silencieusement sans alerte si UnderReplicatedPartitions n'est pas monitoré.
acks=all + min.insync.replicas=2 ✓ Garantie de durabilité : au moins 2 replicas confirment avant que le producer considère l'envoi réussi. ⚠ Configurés séparément, chacun est insuffisant — les trois curseurs (replication, ISR, acks) doivent être cohérents.
KRaft
✓ Supprime la dépendance à ZooKeeper — métadonnées dans __cluster_metadata, même mécanique que les partitions.
⚠ Perte de quorum (2/3 controllers down) = cluster opérationnellement figé même si les données sont lisibles.
🎓 À retenir
UnderReplicatedPartitions > 0 = alerte immédiate — c'est le signal que le cluster est fragile. En état normal, on tolère un broker down. En état sous-répliqué, n'importe quelle panne peut entraîner une perte de données ou une indisponibilité.GcTime et tuner la heap pour éviter les Full GC longs en production.