12 - Kafka en pratique: producteurs, topics et partitions
Kafka est souvent le cœur d’une architecture event-driven. Dans un contexte bancaire, il n’est pas seulement un bus de messages: il devient la colonne vertébrale de la traçabilité et du replay. Ce chapitre se concentre sur la partie producer et la conception des topics: ce sont les décisions qui fixent la qualité du log pour les années à venir.
L’objectif n’est pas d’obtenir “un flux qui marche”, mais un flux fiable, traçable et exploitable, même lors d’incidents. En banque, une mauvaise configuration de producer peut se traduire par des pertes d’événements, des latences non maîtrisées, ou des doublons coûteux à corriger.
Du producer au topic: le chemin d’un event
Un producer sérialise un event, choisit une clé de partition, puis l’envoie vers un topic. Kafka persiste l’event dans une partition, réplique les données et retourne un ACK selon le niveau de garantie. La séquence est simple, mais chaque paramètre a un impact fort sur la fiabilité.
Trois questions fondamentales
Avant d’envoyer le moindre event, le producer doit répondre à trois questions:
1) Quelle est la clé de partition ? Elle définit l’ordre garanti.
2) Quel est le niveau de garantie ? (acks=all, idempotence, transactions).
3) Quel est le contrat de schéma ? (versioning, compatibilité).
Dans un système bancaire, ces choix ne sont pas techniques mais métiers: ils influencent l’audit, la cohérence comptable et la conformité.
Choisir la clé de partition: décision métier
L’ordre n’est garanti qu’à l’intérieur d’une partition. La clé de partition est donc l’élément le plus important pour préserver les invariants métier.
- Pour des opérations de compte:
account_idgarantit l’ordre des débits/crédits. - Pour un flux de virement:
transfer_idsuffit si l’ordre par virement est suffisant, mais ne garantit pas l’ordre des opérations d’un compte. - Pour des flux multi-comptes (ex: virements entre banques): utiliser un identifiant stable qui correspond à l’agrégat métier dominant.
Piège classique: choisir une clé trop générique (ex: customer_id) qui
mélange plusieurs comptes et casse l’ordre critique. Autre piège: une clé trop
concentrée crée un hot partition et limite la scalabilité.
Partitioning & key definition
Une convention simple consiste à utiliser le pattern:
<entity-type>.<entity-key>
Exemples bancaires:
- account.ACC-001
- transfer.T-913
- card.C-5549
Si l’ordre est non critique ou si l’on cherche une distribution équilibrée,
une clé null est acceptable, mais elle supprime toute garantie d’ordering.
Paramètres producer: fiabilité avant performance
Le producer est responsable de la qualité du log. Dans un domaine bancaire, la fiabilité prime sur la latence pure. Les paramètres clés sont:
acks
acks=0: pas de garantie, risque de perte silencieuse.acks=1: ACK du leader seulement.acks=all: ACK après réplication sur l’ISR (in-sync replicas).
Recommandation bancaire: acks=all + min.insync.replicas >= 2.
Idempotence et transactions
L’idempotence garantit qu’un event n’est pas écrit deux fois même en cas de
retry. Avec enable.idempotence=true, Kafka assigne un Producer ID et gère la
séquence. Couplé aux transactions, on peut garantir un flux cohérent de bout en
bout.
En banque, l’idempotence est essentielle pour éviter des doublons comptables. L’outbox pattern complète cette garantie en alignant la transaction métier et la publication Kafka.
Retries et backoff
Les retries ne doivent pas être infinis. En cas d’erreur transitoire, on retente; en cas d’erreur structurelle, on envoie vers une DLQ.
Un design robuste distingue: - erreurs transitoires (réseau, broker indisponible), - erreurs permanentes (schéma invalide, payload corrompu).
Batching et latence
Les paramètres batch.size et linger.ms déterminent la latence vs le débit.
Dans un environnement bancaire, un léger buffering (ex: linger.ms=10) est
acceptable si la latence reste dans le SLA.
Compression
La compression réduit la bande passante et le stockage:
- snappy: rapide, bon compromis.
- lz4: latence très faible.
- zstd: ratio plus élevé, coût CPU plus fort.
Recommandation: snappy pour la plupart des flux temps réel, zstd pour
les flux analytiques ou volumineux.
Contrat d’événements: schéma et metadata
Un event exploitable doit contenir un envelope stable. Exemple:
{
"event_id": "uuid",
"type": "TransferInitiated",
"occurred_at": "2024-01-13T10:00:00Z",
"schema_version": 1,
"correlation_id": "corr-123",
"causation_id": "cmd-456",
"payload": {
"transfer_id": "T-913",
"from_account": "ACC-001",
"to_account": "ACC-987",
"amount_minor": 59090,
"currency": "EUR"
}
}
Le schema_version permet l’évolution contrôlée. Le correlation_id trace un
flux complet (utile pour audit). Le causation_id relie l’event à la command.
Design des topics: public vs private, fact vs delta
Un topic public est un contrat d’intégration. Il doit être stable, versionné, documenté. Un topic private peut évoluer plus vite.
- Fact: fait complet, durable. Exemple:
TransferSettled. - Delta: variation, utile en interne (ex:
balance_delta).
En banque, les events publics doivent presque toujours être des facts pour éviter le couplage aux modèles internes.
Naming des topics
La gouvernance commence par le naming. Un format recommandé:
<environment>.<service>.<domain>.<type>.<action>.<version>
Exemples:
- prod.corebanking.account.evt.opened.v1
- prod.payments.transfer.cmd.initiate.v1
- prod.risk.transfer.evt.scored.v1
Bonnes pratiques de base
- Distinguer commandes et événements dans des topics séparés.
prod.payments.transfer.cmd.initiate.v1prod.payments.transfer.evt.initiated.v1
- Créer un topic de DLQ pour chaque flux critique.
prod.payments.transfer.dlq.v1
- Documenter la rétention et la sensibilité des données.
- Éviter les topics “fourre-tout” qui cassent la gouvernance.
Retention, compaction et log lifecycle
Kafka offre deux modes principaux: - Retention: conserver les events sur une durée fixe (ex: 7 jours). - Compaction: conserver le dernier event par clé.
En banque, les flux transactionnels utilisent la retention longue pour audit. Les flux de référentiels (bénéficiaires, profils KYC) utilisent la compaction pour garder le dernier état.
Une politique de retention doit être cohérente avec les obligations légales. Certains events doivent être conservés plusieurs années, d’autres doivent être purgeables pour conformité RGPD.
Sizing et capacité
Dimensionner un topic n’est pas seulement un problème technique. Il faut estimer: - le volume d’events par seconde, - la taille moyenne de chaque event, - le nombre de partitions nécessaires pour tenir le débit.
Un topic avec trop peu de partitions limite la scalabilité; trop de partitions multiplie les coûts opérationnels et le temps de rebalance. Une banque choisit souvent un compromis: partitions alignées sur la capacité cible + marge.
Producer, outbox et cohérence transactionnelle
Le problème classique est le dual write: la base est mise à jour mais pas
Kafka (ou l’inverse). L’outbox pattern résout ce problème:
1) L’application écrit dans une table outbox dans la même transaction que
l’état métier.
2) Un relay (poller/CDC) publie les events vers Kafka.
3) L’event est marqué comme traité.
Ce mécanisme garantit que l’état et l’event sont cohérents même en cas de panne. Dans un contexte bancaire, c’est souvent un standard de fait.
Sécurité et classification des données
Les events peuvent contenir des données sensibles (PII, montants, IBAN). Le producer doit respecter des règles strictes: - chiffrement TLS en transit, - ACLs sur topics, - masquage/tokenisation des données sensibles, - séparation des topics par niveau de sensibilité.
Exemple: un event public TransferInitiated peut contenir un identifiant
pseudonymisé du compte, tandis que le détail complet reste dans un topic privé.
Exemple bancaire complet: initiation d’un virement
1) L’API reçoit InitiateTransfer.
2) Le service Virements valide les invariants.
3) Une ligne outbox est écrite avec TransferInitiated.
4) Un relay publie dans prod.payments.transfer.evt.initiated.v1.
5) Les consumers (fraude, ledger, notifications) consomment et projettent.
Chaque étape est traçable via correlation_id et peut être rejouée. En cas
d’incident, on peut reconstruire l’état ou relancer un flux de manière fiable.
Configuration avancée du producer
max.in.flight.requests.per.connection
Ce paramètre contrôle le nombre de requêtes non acquittées en vol. En cas de
retries, un max.in.flight trop élevé peut réordonner les messages. Avec
enable.idempotence=true, Kafka gère l’ordre, mais les banques préfèrent
souvent une valeur prudente (ex: 5) pour éviter toute ambiguïté.
delivery.timeout.ms et request.timeout.ms
delivery.timeout.ms définit le délai maximum avant qu’un envoi soit considéré
comme échoué. Un réglage trop bas génère des erreurs inutiles; trop haut, il
retarde la détection d’incidents. En banque, on choisit un délai compatible
avec les SLA (ex: 120s pour les flux critiques).
retries et retry.backoff.ms
Les retries doivent être configurés pour absorber les erreurs transitoires sans
créer de tempêtes. Un retry.backoff.ms modéré évite de surcharger le broker
lors d’une panne partielle.
transactional.id
Si vous utilisez les transactions Kafka, transactional.id doit être stable
par instance. Cela permet de garantir qu’un producer remplacé ne publiera pas
pas de doublons. Cette discipline est essentielle pour des écritures comptables.
Observabilité côté producer
Un producer en production doit être monitoré, au même titre qu’un consumer.
Les métriques utiles incluent:
- record-send-rate et record-send-total pour le débit.
- record-error-rate pour détecter les anomalies.
- batch-size-avg et batch-size-max pour le tuning.
- compression-rate-avg pour évaluer l’efficacité.
Dans une banque, ces métriques doivent être corrélées à la latence end-to-end afin de détecter un goulot d’étranglement en amont du flux.
Scripts et commandes utiles
Exemple de création de topic pour un flux bancaire:
kafka-topics.sh --bootstrap-server localhost:9092 \
--create \
--replication-factor 3 \
--partitions 6 \
--topic prod.payments.transfer.evt.initiated.v1 \
--config retention.ms=604800000 \
--config segment.bytes=1073741824 \
--config cleanup.policy=delete
Cette configuration illustre un topic répliqué (résilience), partitionné (scalabilité), et avec une rétention d’une semaine (audit court). Pour un flux comptable, la rétention peut être bien plus longue.
Exemple de configuration producer (profil bancaire)
acks=all
enable.idempotence=true
max.in.flight.requests.per.connection=5
retries=2147483647
delivery.timeout.ms=120000
request.timeout.ms=30000
linger.ms=10
batch.size=32768
compression.type=snappy
Ce profil privilégie la fiabilité et un débit stable. Il est adapté aux flux
critiques où la perte d’event est inacceptable. Pour des flux moins sensibles,
on peut réduire la latence en ajustant linger.ms ou batch.size.
Formats de sérialisation: JSON, Avro, Protobuf
Le format impacte la compatibilité et la performance. JSON est lisible mais verbeux, Avro et Protobuf offrent un schéma strict et une taille réduite. En banque, où les contracts doivent être stables, Avro ou Protobuf sont souvent préférés. Le Schema Registry permet de valider la compatibilité en CI et réduit les risques de rupture lors des déploiements. Un compromis courant est de garder un envelope JSON lisible et un payload encodé en Avro.
Gestion du backpressure côté producer
Quand les brokers sont saturés ou que les partitions sont en ISR réduite, le producer peut subir des timeouts. Il faut alors appliquer une stratégie de backpressure: limiter le débit, bufferiser localement, ou refuser temporairement les demandes côté API. Dans un flux bancaire critique, il est préférable de ralentir plutôt que de perdre des events. Les métriques d’erreur et de latency doivent déclencher un mécanisme de protection avant que l’API ne dégrade l’expérience client.\n*** End Patch}“}}
Checklist pratique pour producteurs
- La clé de partition est-elle alignée avec l’agrégat métier ?
acks=alletmin.insync.replicassont-ils configurés ?- Idempotence activée ? Transactions nécessaires ?
- Schéma versionné et validé en CI ?
- Rétention/compaction définies selon l’obligation légale ?
- Topic naming conforme et documenté ?
Conclusion
La pratique Kafka côté producer ne se résume pas à “envoyer un message”. Elle engage la cohérence, l’auditabilité et la résilience du système. Dans une banque, ces choix sont structurants pour la conformité et l’exploitation. Maîtriser la clé de partition, la fiabilité et le contrat d’event est la base pour construire un flux event-driven durable.