Messagerie et streaming d'événements
Installer et exploiter Apache Kafka en mode KRaft : mise en place, CLI et supervision
Intermédiaire8 min de lectureMis à jour
Cette page a été traduite de l'anglais avec l'aide de l'IA, puis vérifiée par rapport à l'original. Lire la version anglaise
Un cluster Kafka sans ZooKeeper se résume à quelques processus Java et à un fichier de propriétés chacun, mais ce sont les réglages de ce fichier qui décident si le cluster survit à la perte d'un disque ou à un disque plein. Ce guide installe Kafka 3.x en mode KRaft, d'abord sur un seul nœud puis en cluster de trois brokers, présente les outils en ligne de commande que vous utilisez au quotidien pour les topics, les consumer groups et les offsets, et explique les paramètres de broker, les métriques, les options de sécurité et les étapes de mise à jour qui comptent en production.
Ce que vous allez apprendre
- Formater le stockage et démarrer un broker KRaft ou un nœud combiné broker/contrôleur depuis l'archive ou un conteneur
- Écrire le server.properties d'un cluster de production à trois brokers et trois contrôleurs
- Créer, inspecter et reconfigurer des topics et réinitialiser les offsets d'un consumer group avec les outils CLI
- Définir les valeurs par défaut du broker qui protègent les données : réplication, min.insync.replicas, rétention et création des topics
- Superviser les métriques qui annoncent les pannes : partitions sous-répliquées, état du contrôleur, latence des requêtes et lag des consommateurs
- Activer TLS, SASL et les ACL, et planifier une mise à jour progressive ou une migration depuis ZooKeeper
Kafka traîne une réputation de système difficile à exploiter qui date de l'ère ZooKeeper, quand chaque cluster impliquait deux systèmes distribués, deux configurations de sécurité et une bascule de contrôleur qui pouvait prendre plusieurs minutes. En mode KRaft, prêt pour la production depuis Kafka 3.3 et seul mode disponible en 4.0, un cluster est un ensemble de processus Java identiques dont le rôle est défini dans un unique fichier de propriétés. Ce guide installe Kafka 3.x de cette manière, puis couvre l'outillage du quotidien et les réglages de production que le quickstart passe sous silence. Toutes les commandes sont données pour l'archive Linux ; la variante conteneur est signalée quand elle diffère.
Prérequis et organisation des fichiers
Un broker a besoin d'un JDK — 17 est le choix sûr pour la 3.x et il est obligatoire pour la 4.x —, d'un utilisateur dédié et d'un système de fichiers avec de la place pour log.dirs. Le disque compte davantage que le CPU : Kafka écrit séquentiellement et lit via le page cache, si bien que la configuration habituelle consiste en plusieurs disques ordinaires ou un volume rapide par broker, avec le répertoire de données sur son propre point de montage. Donnez 4 à 6 Go de heap à la JVM et laissez le reste de la mémoire de la machine au page cache ; un heap plus gros rend Kafka plus lent, pas plus rapide.
sudo useradd --system --home /opt/kafka --shell /usr/sbin/nologin kafka
curl -LO https://archive.apache.org/dist/kafka/3.9.0/kafka_2.13-3.9.0.tgz
sudo tar -xzf kafka_2.13-3.9.0.tgz -C /opt
sudo ln -sfn /opt/kafka_2.13-3.9.0 /opt/kafka
sudo mkdir -p /var/lib/kafka && sudo chown -R kafka:kafka /var/lib/kafka /opt/kafka_2.13-3.9.0
Le 2.13 du nom de fichier est la version de Scala avec laquelle le broker a été compilé ; il n'a aucun effet sur les clients Java. Dans l'archive, bin/ contient les scripts CLI, config/kraft/ les exemples de configuration KRaft (server.properties pour un nœud combiné, broker.properties et controller.properties pour des rôles séparés) et libs/ les jars. Kafka 4.0 supprime le sous-répertoire kraft/, puisqu'il n'existe plus d'autre mode.
Un cluster à un seul nœud
Avant de démarrer, un nœud KRaft doit savoir à quel cluster il appartient : c'est le rôle de l'étape de formatage du stockage. Elle écrit dans chaque répertoire de logs un fichier meta.properties contenant l'identifiant du cluster et celui du nœud ; un broker refuse de démarrer sur un répertoire formaté pour un autre cluster, ce qui évite l'accident classique d'un broker égaré qui rejoint la production.
# config/kraft/server.properties — combined broker and controller for development
process.roles=broker,controller
node.id=1
controller.quorum.voters=1@localhost:9093
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
advertised.listeners=PLAINTEXT://localhost:9092
controller.listener.names=CONTROLLER
inter.broker.listener.name=PLAINTEXT
log.dirs=/var/lib/kafka
num.partitions=3
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
KAFKA_CLUSTER_ID=$(bin/kafka-storage.sh random-uuid) # once per cluster; keep it
bin/kafka-storage.sh format -t "$KAFKA_CLUSTER_ID" -c config/kraft/server.properties
bin/kafka-server-start.sh config/kraft/server.properties # foreground; add -daemon to background
La même chose en conteneur, avec l'image officielle que le projet publie depuis la 3.7 :
docker run -d --name kafka -p 9092:9092 \
-e KAFKA_NODE_ID=1 \
-e KAFKA_PROCESS_ROLES=broker,controller \
-e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \
-e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
-e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \
-e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \
-e KAFKA_LOG_DIRS=/var/lib/kafka/data \
-v kafka-data:/var/lib/kafka/data \
apache/kafka:3.9.0
Chaque propriété correspond à une variable d'environnement : on la passe en majuscules, on remplace les points par des underscores et on ajoute le préfixe KAFKA_. Au premier démarrage, l'image formate elle-même le stockage avec un identifiant de cluster généré.
Vérifiez le nœud avec un topic et un aller-retour :
bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic smoke --partitions 1 --replication-factor 1
echo "hello" | bin/kafka-console-producer.sh --bootstrap-server localhost:9092 --topic smoke
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic smoke --from-beginning --max-messages 1
Un cluster de production
Un vrai cluster sépare les rôles. Trois contrôleurs sur de petites machines forment le quorum de métadonnées ; trois brokers ou plus, sur des machines dotées de vrais disques, hébergent les données. Chaque nœud a son propre node.id, unique tous rôles confondus.
# controller.properties on controller nodes 1, 2, 3 (change node.id on each)
process.roles=controller
node.id=1
controller.quorum.voters[email protected]:9093,[email protected]:9093,[email protected]:9093
listeners=CONTROLLER://:9093
controller.listener.names=CONTROLLER
log.dirs=/var/lib/kafka/metadata
# broker.properties on broker nodes 11, 12, 13 (change node.id and advertised host on each)
process.roles=broker
node.id=11
controller.quorum.voters[email protected]:9093,[email protected]:9093,[email protected]:9093
listeners=INTERNAL://:9092,EXTERNAL://:9094
advertised.listeners=INTERNAL://kafka-11.internal:9092,EXTERNAL://kafka-11.example.com:9094
listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:SASL_SSL,CONTROLLER:PLAINTEXT
inter.broker.listener.name=INTERNAL
controller.listener.names=CONTROLLER
log.dirs=/data/kafka-1,/data/kafka-2 # one directory per disk; partitions are spread across them
# Defaults that protect data
default.replication.factor=3
min.insync.replicas=2
offsets.topic.replication.factor=3
transaction.state.log.replication.factor=3
transaction.state.log.min.isr=2
unclean.leader.election.enable=false
auto.create.topics.enable=false # topics are created deliberately, with the right settings
num.partitions=6
log.retention.hours=168
log.segment.bytes=1073741824
message.max.bytes=1048588
Deux de ces paramètres méritent qu'on s'y arrête. auto.create.topics.enable=false empêche une faute de frappe dans le nom de topic d'un producteur de créer en silence un topic à une seule partition et sous-répliqué. Et min.insync.replicas=2 est la moitié du contrat de durabilité côté broker : avec lui, un producteur en acks=all est refusé quand moins de deux réplicas sont vivants, au lieu de s'entendre dire qu'un enregistrement est en sécurité alors qu'il n'existe que sur une machine.
Kafka 3.9 a introduit l'appartenance dynamique au quorum (controller.quorum.bootstrap.servers au lieu d'une liste statique controller.quorum.voters, plus kafka-metadata-quorum.sh add-controller), qui permet de remplacer un contrôleur sans redémarrer les autres. La liste statique fonctionne toujours et reste plus simple à appréhender pour un premier cluster.
Faites tourner chaque nœud sous systemd avec Restart=on-failure, un LimitNOFILE généreux (Kafka garde un descripteur de fichier ouvert par segment et par index) et KAFKA_HEAP_OPTS="-Xms4g -Xmx4g" dans l'environnement.
L'exploitation quotidienne en ligne de commande
Chaque script de bin/ dialogue avec le cluster via --bootstrap-server ; il n'y a pas de port d'administration séparé. Les quatre que vous utiliserez le plus :
Topics. Créez-les avec des paramètres explicites, décrivez-les pour voir les leaders et les réplicas synchronisés, modifiez-les pour ajouter des partitions ou changer leur configuration.
bin/kafka-topics.sh --bootstrap-server kafka-11.internal:9092 --create --topic orders \
--partitions 12 --replication-factor 3 --config min.insync.replicas=2 --config retention.ms=1209600000
bin/kafka-topics.sh --bootstrap-server kafka-11.internal:9092 --describe --topic orders
# Topic: orders Partition: 0 Leader: 11 Replicas: 11,12,13 Isr: 11,12,13
# A partition whose Isr is shorter than Replicas is under-replicated
bin/kafka-configs.sh --bootstrap-server kafka-11.internal:9092 --alter --entity-type topics \
--entity-name orders --add-config cleanup.policy=compact,delete
Consumer groups. La description montre, pour chaque partition, l'offset commité, l'offset de fin de log, le lag et le membre qui la détient ; la réinitialisation des offsets permet de rejouer ou de sauter des messages.
bin/kafka-consumer-groups.sh --bootstrap-server kafka-11.internal:9092 --describe --group billing
# GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
# billing orders 0 1204 1210 6 billing-1-… /10.0.1.5 billing
# Rewind the whole group to two hours ago — the group must be stopped first
bin/kafka-consumer-groups.sh --bootstrap-server kafka-11.internal:9092 --group billing \
--topic orders --reset-offsets --to-datetime 2026-09-07T07:00:00.000 --execute
# Other targets: --to-earliest, --to-latest, --to-offset N, --shift-by -100, --by-duration PT1H
Console producer et console consumer. Pour vérifier que les données circulent et inspecter un topic de visu ; --property print.key=true --property print.timestamp=true côté consommateur et --property parse.key=true --property key.separator=: côté producteur rendent les clés visibles.
Quorum de métadonnées. bin/kafka-metadata-quorum.sh --bootstrap-server kafka-11.internal:9092 describe --status affiche le contrôleur actif, les votants, leur retard sur le leader et la version courante des métadonnées ; c'est la première commande à lancer quand le cluster se comporte mal.
Deux autres commandes méritent leur place dans un runbook : kafka-reassign-partitions.sh déplace des réplicas entre brokers quand vous ajoutez ou retirez un nœud (il n'y a pas de rééquilibrage automatique), et kafka-leader-election.sh rétablit les leaders préférés après le retour d'un broker, pour que le trafic soit de nouveau réparti équitablement.
Supervision
Les brokers exposent des centaines de métriques JMX ; un exporteur JMX pour Prometheus ou l'agent de votre outil de supervision les transforme en tableaux de bord. Une courte liste suffit à anticiper la plupart des incidents :
| Métrique (JMX) | Valeur saine | Ce que signifie un écart |
|---|---|---|
kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions | 0 | Un follower est en retard ou arrêté ; la durabilité avec acks=all est réduite et, à min.insync.replicas, les producteurs seront refusés |
kafka.controller:type=KafkaController,name=ActiveControllerCount | 1 sur l'ensemble du cluster | 0 signifie aucun contrôleur — ni élection de leader, ni modification de topic ; plus de 1 signale un split-brain |
kafka.server:type=ReplicaManager,name=OfflinePartitionsCount | 0 | Des partitions sans leader ; leurs producteurs et consommateurs échouent |
kafka.network:type=RequestMetrics,name=TotalTimeMs,request=Produce (p99) | Quelques dizaines de ms au plus | Latence du disque ou de la réplication ; les producteurs approchent de delivery.timeout.ms |
kafka.server:type=KafkaRequestHandlerPool,name=RequestHandlerAvgIdlePercent | Au-dessus de 0,3 | Threads du broker saturés ; ajoutez des brokers ou réduisez le nombre de partitions par broker |
kafka.log:type=LogFlushStats,name=LogFlushRateAndTimeMs | Stable | Un temps de flush qui augmente signifie que le disque est le goulet d'étranglement |
Lag des consommateurs par groupe (kafka-consumer-groups.sh ou records-lag-max côté consommateur) | Stable ou en baisse | Les consommateurs sont trop lents, arrêtés ou bloqués sur un message empoisonné |
Posez aussi une alerte sur l'occupation disque de chaque chemin de log.dirs : un broker dont le disque de données se remplit met le répertoire concerné hors ligne, et avec un seul répertoire, c'est tout le broker qui tombe. Les limites de rétention sont votre protection ; dimensionnez-les par rapport au disque, avec de la marge pour le pic du plus gros topic.
Sécurité
Par défaut, un listener Kafka est en clair et sans authentification. Le sécuriser demande trois couches, toutes configurées par listener :
- Chiffrement avec TLS :
ssl.keystore.locationetssl.truststore.locationsur le broker,SSLouSASL_SSLdanslistener.security.protocol.map. - Authentification avec SASL.
SCRAM-SHA-512stocke les identifiants dans les métadonnées du cluster (kafka-configs.sh --alter --add-config 'SCRAM-SHA-512=[password=...]' --entity-type users --entity-name orders),OAUTHBEARERs'intègre à un fournisseur d'identité etGSSAPIà Kerberos. Le mTLS avec certificats clients est une quatrième option, qui se passe entièrement de SASL. - Autorisation avec les ACL :
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizersur chaque nœud,super.userspour les opérateurs etkafka-acls.sh --add --allow-principal User:orders --operation Write --topic orderspour les applications. Pour les consommateurs, accordezReadsur les topics etReadsur le consumer group ; oublier l'ACL du groupe est la cause la plus fréquente d'uneGroupAuthorizationException.
Gardez le listener des contrôleurs sur un réseau privé : il transporte le log de métadonnées et, dans un déploiement à rôles séparés, n'a aucun besoin d'être joignable par les clients.
Mises à jour et migration depuis ZooKeeper
Les brokers se mettent à jour un par un : arrêtez le broker, installez la nouvelle version, démarrez-le, attendez que UnderReplicatedPartitions revienne à zéro, passez au suivant. Les clients continuent de fonctionner pendant toute l'opération, car le protocole est négocié à chaque connexion. Quand tous les nœuds tournent sur la nouvelle version, relevez la version des métadonnées — bin/kafka-features.sh --bootstrap-server ... upgrade --metadata 3.9 — pour débloquer les fonctionnalités apportées par la nouvelle release ; d'ici là, le cluster se comporte comme l'ancienne version, et cette étape peut attendre aussi longtemps que vous le souhaitez.
Les clusters encore sous ZooKeeper doivent migrer avant la 4.0, qui ne sait plus du tout lire ZooKeeper. La procédure documentée provisionne un quorum de contrôleurs KRaft en mode migration, le laisse copier les métadonnées depuis ZooKeeper, redémarre les brokers un par un en mode KRaft, puis sort enfin les contrôleurs du mode migration ; un retour arrière reste possible jusqu'à cette dernière étape. Traitez-la comme un projet, avec une répétition sur une copie de la production, et non comme une simple fenêtre de maintenance.
Erreurs courantes
advertised.listenerslaissé à localhost. Le grand classique du « ça marche sur la machine mais nulle part ailleurs » ; renseignez une adresse que les clients peuvent joindre.- Facteur de réplication 1 pour les topics internes. Le
offsets.topic.replication.factor=1du quickstart, en production, signifie que la perte d'un seul broker fait perdre la position de tous les consumer groups. Passez les trois facteurs de réplication internes à 3. auto.create.topics.enablelaissé activé. Les fautes de frappe deviennent des topics sous-répliqués permanents ; tôt ou tard, quelqu'un consomme le mauvais.- Un heap dimensionné comme pour une base de données. 4 à 6 Go suffisent largement ; c'est le page cache qui fait le vrai travail. Un très gros heap entraîne de longues pauses du garbage collector qui, vues du contrôleur, ressemblent à un broker mort.
- Ajouter un broker en s'attendant à ce qu'il prenne de la charge. Les partitions existantes restent où elles sont tant que vous n'avez pas lancé
kafka-reassign-partitions.sh. - Aucune alerte sur le lag. Un consommateur mort depuis une semaine est découvert quand sa fenêtre de rétention expire et que les données ont disparu.
Points clés à retenir
- KRaft supprime ZooKeeper : formatez le stockage de chaque nœud avec l'identifiant du cluster, définissez
process.roles,node.idet le quorum de contrôleurs, puis démarrez le processus. - En développement, un seul nœud combiné suffit ; en production, on déploie trois contrôleurs dédiés et au moins trois brokers, chacun avec des
advertised.listenersque les clients peuvent réellement joindre. default.replication.factor=3,min.insync.replicas=2, des topics internes répliqués,auto.create.topics.enable=falseet une rétention explicite sont les réglages de broker qui protègent les données.kafka-topics.sh,kafka-consumer-groups.sh,kafka-configs.shetkafka-metadata-quorum.shcouvrent l'essentiel du travail quotidien, y compris la réinitialisation des offsets d'un groupe pour rejouer des messages.- Surveillez les partitions sous-répliquées et hors ligne, le nombre de contrôleurs actifs, la latence de production, le pourcentage d'inactivité des handlers, l'occupation disque et le lag des consommateurs.
- Sécurisez les listeners avec TLS, SASL et les ACL ; mettez à jour les brokers un par un et relevez ensuite la version des métadonnées ; migrez les derniers clusters ZooKeeper avant de passer à la 4.x.
Sources et lectures complémentaires
Questions fréquentes
- Combien de contrôleurs faut-il à un cluster KRaft ?
- Trois pour la plupart des clusters, cinq pour les très gros ou les très critiques. Raft a besoin d'une majorité pour avancer : trois contrôleurs tolèrent donc une panne, cinq en tolèrent deux. Un seul contrôleur suffit en développement. Les nœuds combinés broker/contrôleur sont acceptables pour de petits clusters, mais en production on fait généralement tourner les contrôleurs comme des processus séparés et peu chargés, pour que la charge des brokers ne puisse pas retarder les décisions sur les métadonnées.
- Pourquoi mes clients se connectent-ils depuis la machine hôte mais pas depuis d'autres machines ou conteneurs ?
- Parce que advertised.listeners indique aux clients où se connecter pour les requêtes suivantes, et que sa valeur par défaut est celle de listeners, souvent localhost. Le client réussit son bootstrap, reçoit localhost:9092 comme adresse du leader, puis échoue. Renseignez advertised.listeners avec un nom d'hôte ou une IP que tous les clients peuvent résoudre et joindre, avec des listeners distincts pour le trafic interne et externe s'ils diffèrent.
- Peut-on réduire le nombre de partitions d'un topic ?
- Non. On ne peut qu'en ajouter. Pour en réduire le nombre, créez un nouveau topic avec le nombre voulu, copiez les données avec un couple consommateur-producteur ou MirrorMaker, basculez consommateurs et producteurs, puis supprimez l'ancien topic. Comme les clés sont affectées aux partitions par hachage, la copie modifie l'ordre par clé par rapport à l'ancien topic.
- Faut-il mettre à jour les clients quand on met à jour les brokers ?
- Non. Le protocole Kafka est versionné et les brokers acceptent les requêtes des clients plus anciens ; des clients plus récents que le broker fonctionnent aussi, mais sans utiliser les fonctionnalités qui manquent au broker. Mettez d'abord à jour les brokers, un par un, puis relevez la version des métadonnées avec kafka-features.sh, et enfin mettez à jour les clients à votre rythme.