Maîtrise de la configuration des topics Kafka : Guide complet

Guide pratique sur les partitions, la réplication, la rétention, la compaction et les modifications sécurisées de configuration des topics Kafka.

Maîtrise de la configuration des topics Kafka : Guide complet

La configuration des topics Kafka détermine comment vos données sont stockées, copiées, expirées, compactées et consommées. Vous pouvez utiliser Kafka avec les paramètres par défaut pendant un certain temps, surtout dans un cluster de développement, mais les topics de production nécessitent plus d'attention. Un mauvais nombre de partitions peut piéger une charge de travail intense. Une réplication faible peut transformer une panne de courtier en perte de données. Une rétention trop laxiste peut remplir les disques. La compaction peut vous surprendre si les clés sont manquantes ou incohérentes.

L'approche utile pour aborder la configuration des topics Kafka n'est pas de mémoriser chaque paramètre. Commencez par les questions que se pose un système réel : de quel parallélisme ai-je besoin, combien de temps les données doivent-elles rester disponibles, combien de données puis-je me permettre de stocker, que se passe-t-il en cas de panne d'un courtier, et les consommateurs ont-ils besoin d'un historique complet des événements ou seulement de la dernière valeur par clé ?

Un topic est divisé en partitions. Chaque partition est un journal ordonné. Kafka préserve l'ordre au sein d'une partition, pas sur l'ensemble du topic. Si tous les événements d'un client doivent être traités dans l'ordre, utilisez une clé stable comme customer_id pour que ces événements atterrissent dans la même partition. Si vous utilisez des clés aléatoires, vous pouvez obtenir une meilleure distribution mais perdre l'ordre par entité.

Le nombre de partitions est l'un des premiers choix que les gens regrettent. Plus de partitions permettent un plus grand parallélisme des consommateurs car, au sein d'un groupe de consommateurs, une partition n'est consommée que par un seul membre du groupe à la fois. Si un topic a six partitions, un groupe de consommateurs peut utiliser activement jusqu'à six consommateurs pour ce topic. L'ajout d'un septième consommateur n'augmentera pas la consommation pour ce topic à moins qu'il n'y ait d'autres partitions assignées.

Plus de partitions ont aussi un coût. Elles augmentent les métadonnées, les fichiers ouverts, le travail de réplication, le travail d'élection du leader et le temps de récupération après les pannes de courtier. Un nombre très élevé de partitions peut ralentir les opérations du cluster même si chaque partition a un trafic modeste. Il n'y a pas de nombre universel idéal. Un petit topic interne peut se contenter de trois partitions. Un flux d'événements chargé peut nécessiter des dizaines. Une très grande installation Kafka peut en utiliser bien plus, mais cela doit découler du débit mesuré et de la capacité opérationnelle, pas d'une habitude.

Créez un topic avec des paramètres explicites :

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic user-events.v1   --partitions 12   --replication-factor 3   --config min.insync.replicas=2

Le nom du topic doit également porter une certaine intention. Des noms comme events ou data deviennent inutiles une fois que le cluster grandit. user-events.v1, billing-invoices.v1 ou inventory-adjustments.v1 indiquent aux futurs opérateurs ce qu'est le flux et vous laissent une marge pour un changement de schéma cassant ultérieur.

Le facteur de réplication contrôle le nombre de copies que Kafka conserve pour chaque partition. En production, 3 est une valeur par défaut courante car elle permet à un courtier de tomber en panne tout en laissant une autre réplique disponible. Cela ne signifie pas que vous pouvez ignorer les paramètres du producteur. Si les producteurs utilisent acks=1, Kafka peut accuser réception des enregistrements avant que les followers ne les aient copiés. Pour les topics importants, associez un facteur de réplication de trois à min.insync.replicas=2 au niveau du topic et à acks=all du producteur.

min.insync.replicas est souvent mal compris. Il ne crée pas de répliques. Il indique combien de répliques synchronisées doivent être disponibles pour qu'une écriture avec acks=all réussisse. Avec un facteur de réplication de trois et min.insync.replicas=2, le topic peut tolérer qu'un courtier soit indisponible. S'il ne reste qu'une seule réplique synchronisée, Kafka doit rejeter les écritures fortes au lieu d'accepter des données avec trop peu de copies sûres.

Les paramètres de rétention décident quand Kafka peut supprimer les anciens segments de journal. La rétention basée sur le temps est contrôlée par retention.ms au niveau du topic. La rétention basée sur la taille est contrôlée par retention.bytes. Les anciens noms au niveau du courtier comme log.retention.ms sont des valeurs par défaut du courtier ; la configuration du topic utilise couramment retention.ms.

Par exemple, pour conserver un topic pendant sept jours :

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.ms=604800000

Pour limiter le stockage par partition, utilisez retention.bytes :

kafka-configs.sh --alter   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1   --add-config retention.bytes=10737418240

N'oubliez pas que retention.bytes est généralement par partition, pas la taille totale du topic. Un topic avec douze partitions et retention.bytes=10 Go peut utiliser environ 120 Go avant réplication, et environ 360 Go avec un facteur de réplication de trois. C'est le genre de détail qui provoque des alertes de disque surprises.

Kafka supprime les données par segment de journal, pas enregistrement par enregistrement. Si vous définissez une courte période de rétention mais de grands segments, la suppression peut ne pas se produire à la minute exacte que vous attendez. Les paramètres de segment tels que segment.bytes et segment.ms influencent le moment où Kafka passe à un nouveau segment, et seuls les segments fermés sont éligibles à la suppression ou à la compaction. Des segments plus petits peuvent rendre le nettoyage plus réactif, mais ils ajoutent une surcharge.

cleanup.policy décide ce que Kafka fait des anciennes données. La valeur par défaut est delete, qui supprime les anciens segments en fonction de la rétention. compact conserve le dernier enregistrement pour chaque clé et supprime éventuellement les enregistrements plus anciens avec la même clé. Vous pouvez également utiliser delete,compact pour les topics qui ont besoin d'une compaction plus une fenêtre de rétention.

La compaction est utile pour les flux de type état : mises à jour de profil utilisateur, valeurs de fonctionnalités, paramètres de compte ou événements de changement de base de données indexés par clé primaire. C'est un mauvais choix pour un historique d'événements où chaque événement compte. Si vous compactez un journal d'audit, les événements plus anciens pour la même clé peuvent éventuellement disparaître. Cela peut être exactement ce qu'il ne faut pas faire pour la conformité ou le débogage.

La compaction dépend également des clés. Un topic compacté avec des clés nulles ou incohérentes ne se comportera pas comme un journal des modifications clé-valeur propre. Si les producteurs envoient des mises à jour utilisateur parfois indexées par user_id et parfois par email, Kafka voit des clés différentes. Il ne peut pas en déduire qu'elles représentent le même utilisateur.

La compression peut être définie par les producteurs, et un topic peut définir compression.type pour contrôler le comportement du courtier. Les valeurs courantes incluent producer, gzip, snappy, lz4 et zstd, selon la version de Kafka. De nombreuses équipes laissent le topic à producer et standardisent la compression du producteur. lz4 et zstd sont des choix courants, mais la bonne réponse dépend du budget CPU, de la forme des messages et de la pression réseau.

Vous pouvez inspecter la configuration d'un topic comme ceci :

kafka-configs.sh --describe   --bootstrap-server broker1:9092   --entity-type topics   --entity-name user-events.v1

Et inspecter le placement des partitions comme ceci :

kafka-topics.sh --describe   --bootstrap-server broker1:9092   --topic user-events.v1

Utilisez les deux commandes. Les configurations de topic vous indiquent les règles de rétention, de compaction et d'ISR. La description du topic vous indique les leaders, les répliques et l'état ISR. Un topic peut avoir une configuration parfaite et être encore malsain parce que les répliques sont désynchronisées.

Certaines modifications sont faciles. La rétention, la politique de compaction, min.insync.replicas et plusieurs autres configurations de topic peuvent être modifiées dynamiquement. Certaines modifications nécessitent plus de prudence. Vous pouvez augmenter le nombre de partitions, mais vous ne pouvez pas le diminuer en toute sécurité avec une simple commande. L'augmentation des partitions modifie également la distribution des clés pour les enregistrements futurs car le calcul de partitionnement a plus de partitions cibles. Les enregistrements existants restent où ils sont ; les nouveaux enregistrements pour la même clé peuvent aller vers une partition différente après l'augmentation, selon le partitionneur. Si un ordre strict par clé est important lors du changement, planifiez soigneusement.

Les changements de facteur de réplication sont un travail opérationnel. L'augmentation des répliques pour un topic existant signifie que Kafka doit copier les données existantes vers de nouveaux courtiers. Cela peut représenter beaucoup d'E/S. Utilisez les outils de réaffectation, surveillez la progression et limitez si nécessaire. Ne démarrez pas une grande réaffectation pendant un trafic de pointe à moins de savoir que le cluster a suffisamment de capacité de réserve.

Pour un topic d'événements de production normal, un point de départ pratique pourrait ressembler à ceci :

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic payments-authorized.v1   --partitions 24   --replication-factor 3   --config min.insync.replicas=2   --config retention.ms=1209600000   --config cleanup.policy=delete

Cela signifie : suffisamment de partitions pour le parallélisme, trois copies pour la disponibilité, deux répliques synchronisées requises pour les écritures fortes, quatorze jours de rétention, et pas de compaction car chaque événement d'autorisation de paiement compte.

Pour un topic d'état, la forme est différente :

kafka-topics.sh --create   --bootstrap-server broker1:9092   --topic user-preferences.v1   --partitions 12   --replication-factor 3   --config min.insync.replicas=2   --config cleanup.policy=compact

Ce topic doit être indexé par ID utilisateur. Les consommateurs reconstruisant l'état peuvent lire le journal compacté et voir éventuellement la dernière valeur pour chaque utilisateur. Ils ne doivent pas s'attendre à ce que chaque changement de préférence historique reste pour toujours.

La meilleure configuration de topic est ennuyeuse à exploiter. Elle a suffisamment de partitions mais pas des milliers sans raison. Elle a une réplication qui correspond à la valeur des données. Elle a une rétention qui correspond aux besoins de récupération et de conformité. Elle utilise la compaction uniquement lorsque les clés sont significatives. Elle est décrite dans le code ou la documentation afin qu'un autre ingénieur puisse la recréer sans deviner.

Une habitude de révision utile est d'écrire l'histoire du consommateur avant de choisir les paramètres du topic. Qui lit ce topic ? Ont-ils besoin de rejouer depuis le début ? Combien de temps prendrait une reconstruction complète ? Le système source peut-il republier les anciennes données ? Si un consommateur est hors service pendant trois jours, Kafka doit-il encore avoir les enregistrements manqués ? Ces réponses déterminent la rétention plus honnêtement qu'un paramètre par défaut de sept jours.

Considérez un consommateur de détection de fraude qui lit les événements de paiement. S'il est hors service pendant six heures, vous voulez presque certainement qu'il rattrape son retard depuis Kafka. S'il est hors service pendant trente jours, vous pouvez vous attendre à un processus de réapprovisionnement séparé depuis la base de données de paiement. Ce topic pourrait avoir besoin de deux semaines de rétention, pas pour toujours. Un topic de journal d'audit de sécurité peut avoir une exigence différente, peut-être l'expédition vers un stockage d'objets pour une rétention à long terme tandis que Kafka ne conserve que la fenêtre de relecture à chaud.

La taille des messages fait également partie de la conversation sur les topics. Kafka peut gérer des enregistrements plus volumineux lorsqu'il est configuré pour cela, mais les messages volumineux affectent les producteurs, les courtiers, les consommateurs, la réplication et la mémoire de récupération. Si les équipes commencent à mettre des blobs JSON de plusieurs mégaoctets ou des fichiers encodés dans un topic, ne vous contentez pas d'augmenter max.message.bytes et de passer à autre chose. Demandez-vous si la charge utile appartient au stockage d'objets avec une référence dans Kafka. Kafka est généralement meilleur pour déplacer des événements, pas pour agir comme un magasin de blobs.

L'évolution du schéma n'est pas un paramètre de configuration du topic, mais elle façonne la conception du topic. Un topic nommé avec un suffixe de version, comme orders.v1, vous donne une porte de sortie lorsqu'un changement cassant est inévitable. Les changements compatibles peuvent rester dans le même topic si les consommateurs et les producteurs suivent une politique de schéma. Les changements cassants ne doivent pas être glissés dans le même topic parce qu'une équipe contrôle le producteur. Kafka découple les systèmes, mais seulement si le contrat est respecté.

Enfin, documentez la propriété du topic. Chaque topic de production doit avoir une équipe propriétaire, des producteurs attendus, des consommateurs attendus, une raison de rétention et des notes sur la sensibilité des données. Cela semble administratif jusqu'à ce que le disque se remplisse à 02h00 et que personne ne sache si un topic peut être raccourci, supprimé, compacté ou limité. Une bonne configuration de topic est en partie technique et en partie mémoire opérationnelle.

Une dernière vérification avant de publier un topic consiste à parcourir un scénario de panne. Si un courtier disparaît, les producteurs peuvent-ils encore écrire ? Si un groupe de consommateurs est hors service pendant le week-end, la rétention couvrira-t-elle l'écart ? Si un producteur envoie de mauvaises données, les consommateurs peuvent-ils sauter, mettre en quarantaine ou rejouer en toute sécurité ? Si le topic croît deux fois plus vite que prévu, quelle limite protège le cluster : le temps de rétention, les octets de rétention, les quotas ou une alerte ?

Les quotas méritent d'être mentionnés car la configuration du topic seule ne protège pas un cluster partagé d'un producteur bruyant. Kafka prend en charge les quotas clients qui peuvent limiter les taux de production et de récupération. Si plusieurs équipes partagent un cluster, les quotas peuvent empêcher une relecture accidentelle ou un producteur incontrôlable de submerger les courtiers. Ils doivent être associés à des alertes afin que les équipes sachent qu'elles sont limitées au lieu de blâmer silencieusement Kafka.

N'oubliez pas la politique de suppression. Certains clusters désactivent la suppression de topics au niveau du courtier pour éviter les accidents. Cela peut être judicieux, mais cela signifie que les topics abandonnés doivent être traités via un processus de nettoyage contrôlé. Un inventaire des topics tous les mois ou tous les trimestres peut récupérer une quantité surprenante d'espace disque, en particulier dans les clusters de développement et de staging où les expériences laissent derrière elles d'anciens topics.