Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Idempotence et livraison au moins une fois

Après cette leçon: Je peux concevoir un consommateur qui reste correct quand un message est relu.

Leçon de 60 min5 commandesLab Kafka : topics, producteurs, consommateurs, partitions et offsets dans le navigateur

Un message qui arrive deux fois

La livraison au moins une fois garantit qu’un message arrive, quitte à arriver plusieurs fois. Un consommateur idempotent donne le même résultat qu’il lise un message une fois ou dix fois.

Un virement de 50 € est écrit dans un journal. Si le consommateur tombe après avoir débité le compte mais avant de noter sa position, il relit le message et débite 50 € une seconde fois.

À la fin de cette leçon

Remarque

Je peux concevoir un consommateur qui reste correct quand un message est relu.

Mots clés

MotCe que ça veut dire
Au moins une foisun message arrive, parfois en plusieurs exemplaires
Idempotentqui donne le même résultat s’il est répété
Doublonun message reçu une seconde fois
Décalagele numéro d’un événement dans sa partition
Validationl’enregistrement du décalage jusqu’où l’on a lu

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Un réessai peut créer un doublon

Un producteur envoie un événement et attend la confirmation. Si elle n’arrive pas à temps, il ne sait pas si l’événement a été écrit. Le plus sûr est de le renvoyer : c’est un réessai.

Si le premier envoi avait réussi, le journal contient maintenant deux fois le même événement. C’est un doublon.

Créer un topic d’une partition

Commande
curl -s -X POST -H "Content-Type: application/json" -d '{"name":"virements","partitions":1,"replicationFactor":1,"configs":{}}' http://kafka-ui:8080/api/clusters/lab/topics -o /dev/null -w "%{http_code}\n"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Envoyer le virement 42

Commande
curl -s -X POST -H "Content-Type: application/json" -d '{"partition":0,"key":"v42","value":"payer","headers":{},"keySerde":"String","valueSerde":"String"}' http://kafka-ui:8080/api/clusters/lab/topics/virements/messages -o /dev/null -w "%{http_code}\n"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le renvoyer, comme après un délai dépassé

Commande
curl -s -X POST -H "Content-Type: application/json" -d '{"partition":0,"key":"v42","value":"payer","headers":{},"keySerde":"String","valueSerde":"String"}' http://kafka-ui:8080/api/clusters/lab/topics/virements/messages -o /dev/null -w "%{http_code}\n"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Voir combien d’événements contient la partition

Commande
curl -s http://kafka-ui:8080/api/clusters/lab/topics/virements | grep -o '"partition":[0-9]*\|"offsetMax":[0-9]*'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Relire le journal depuis le début

Commande
curl -s -N "http://kafka-ui:8080/api/clusters/lab/topics/virements/messages/v2?seekType=BEGINNING&partitions=0&limit=10" | grep -o '"partition":[0-9]*,"offset":[0-9]*\|"value":"[a-z]*"'

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Valider avant ou après le traitement

Un consommateur note jusqu’où il a lu : c’est la validation de son décalage. Après une panne, il reprend à ce décalage.

S’il valide après avoir traité, une panne entre les deux fait relire le message : au moins une fois. S’il valide avant, la même panne le fait sauter : au plus une fois.

Exemple : où tombe le consommateur

Moment de la panneCe qui arrive au messageNom du comportement
Après traiter, avant validerIl est relu et traité deux foisAu moins une fois
Après valider, avant traiterIl n’est jamais traitéAu plus une fois
Après traiter et validerIl est traité une seule foisCas normal

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Rejouer une panne du consommateur

Code: python
# Un consommateur traite des débits, puis valide son décalage. Il tombe avant de valider le 2e.
montants = [50, 20, 30]
decalage_valide = 1
traites = [50, 20]
# Au redémarrage, il reprend au dernier décalage validé.
for montant in montants[decalage_valide:]:
    traites.append(montant)
total = 0
for montant in traites:
    total = total + montant
print("Messages traités :", traites)
print("Total débité :", total, "au lieu de", 100)

Un identifiant rend le traitement idempotent

On ne peut pas empêcher tous les doublons, mais on peut les rendre sans effet. Chaque message porte un identifiant unique. Le consommateur garde la liste des identifiants déjà traités et ignore un identifiant qu’il a déjà vu.

Le traitement devient idempotent : le répéter ne change plus le résultat.

Ignorer un identifiant déjà vu

Code: python
# Chaque message porte un identifiant. On ne traite jamais deux fois le même.
messages = [["v1", 50], ["v2", 20], ["v2", 20], ["v3", 30]]
deja_vus = {}
total = 0
for message in messages:
    identifiant = message[0]
    if identifiant in deja_vus:
        print("Doublon ignoré :", identifiant)
    else:
        deja_vus[identifiant] = True
        total = total + message[1]
print("Total débité :", total)
# Ajoutez ["v3", 30] à la fin de la liste puis relancez.

Une erreur fréquente

Attention

On croit souvent qu’un message ne peut être lu qu’une seule fois. Une panne ou une confirmation perdue suffit à le faire relire. On obtient l’effet « une seule fois » en acceptant les doublons et en les ignorant.

À propos de ce labo et de sa source: Lab Kafka : topics, producteurs, consommateurs, partitions et offsets dans le navigateur

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.