La vente arrivée en retard
Un système de flux compte des événements dans des fenêtres de temps, et un événement peut arriver en retard. Le choix de la fenêtre où le ranger change les chiffres.
Une caisse perd le réseau quelques secondes, puis envoie une vente faite à 10:00:58. Elle arrive après une vente faite à 10:01:02. À quelle minute appartient-elle : celle où elle a eu lieu, ou celle où elle est arrivée ? Vous comptez ici des deux façons et vous voyez l’écart.
À la fin de cette leçon
Remarque
Je peux compter des événements dans des fenêtres fixes de temps d’événement et dire lesquels sont tardifs.
Mots-clés
| Mot | Ce que ça veut dire |
|---|---|
| Temps d’événement | le moment où la chose s’est vraiment passée |
| Temps de traitement | le moment où le système a reçu l’événement |
| Fenêtre fixe | une tranche de temps qui ne chevauche jamais la suivante |
| Événement tardif | un événement qui arrive après un plus récent |
| Tolérance de retard | le temps pendant lequel une fenêtre attend les événements tardifs |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Tout événement a deux horloges
Le temps d’événement est le moment où la chose s’est passée, par exemple l’instant d’une vente. Le temps de traitement est le moment où votre système a reçu l’événement.
Le plus souvent, ils sont proches. Une panne de réseau, un téléphone sans signal ou un serveur chargé peuvent les écarter. Kafka garde les événements dans l’ordre d’arrivée : ses décalages suivent le temps de traitement, pas le temps d’événement.
Exemple : cinq ventes
| Décalage | Article | Temps d’événement (secondes) | Arrivée |
|---|---|---|---|
| 0 | pain | 5 | première |
| 1 | lait | 62 | deuxième |
| 2 | cafe | 58 | troisième, après 62 |
| 3 | riz | 125 | quatrième |
| 4 | oeufs | 70 | cinquième, après 125 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Créer un topic d’une seule partition
curl -s -X POST -H "Content-Type: application/json" -d '{"name":"caisses","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 les cinq ventes dans l’ordre d’arrivée
for e in "5 pain" "62 lait" "58 cafe" "125 riz" "70 oeufs"; do curl -s -X POST -H "Content-Type: application/json" -d "{\"partition\":0,\"key\":\"caisse\",\"value\":\"$e\",\"headers\":{},\"keySerde\":\"String\",\"valueSerde\":\"String\"}" http://kafka-ui:8080/api/clusters/lab/topics/caisses/messages -w "%{http_code}\n"; doneAffiché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 les décalages
curl -s http://kafka-ui:8080/api/clusters/lab/topics/caisses | 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.
Lire le topic depuis le début
curl -s -N "http://kafka-ui:8080/api/clusters/lab/topics/caisses/messages/v2?seekType=BEGINNING&limit=10" | grep -o '"offset":[0-9]*\|"value":"[^"]*"'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.
Compter les minutes d’horloge du broker
curl -s -N "http://kafka-ui:8080/api/clusters/lab/topics/caisses/messages/v2?seekType=BEGINNING&limit=10" | grep -o '"timestamp":"[^"]*"' | cut -c25-29 | sort -u | wc -lAffiché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.
Une fenêtre est une tranche de temps d’événement
Pour compter par minute, vous coupez le temps en fenêtres de 60 secondes. Une fenêtre fixe commence où la précédente finit : chaque événement est dans une seule.
Le début de la fenêtre d’un événement est son temps moins le reste de la division par la taille. Le temps 62 donne 62 moins 2 : la fenêtre commence à 60.
Exemple : fenêtres de 60 secondes
| Fenêtre | Début | Fin (exclue) | Articles |
|---|---|---|---|
| Première | 0 | 60 | pain, cafe |
| Deuxième | 60 | 120 | lait, oeufs |
| Troisième | 120 | 180 | riz |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Compter les événements de chaque fenêtre
# Chaque événement est [temps en secondes, article], dans l’ordre d’arrivée.
evenements = [[5, "pain"], [62, "lait"], [58, "cafe"], [125, "riz"], [70, "oeufs"]]
taille = 60
compte = {}
for evenement in evenements:
debut = evenement[0] // taille * taille
if debut in compte:
compte[debut] = compte[debut] + 1
else:
compte[debut] = 1
print(compte)
# Mettez taille à 30 puis relancez.
Compter les fenêtres depuis le topic lui-même
curl -s -N "http://kafka-ui:8080/api/clusters/lab/topics/caisses/messages/v2?seekType=BEGINNING&limit=10" | grep -o '"value":"[^"]*"' | cut -d'"' -f4 | while read t article; do echo $((t / 60)); done | sort -n | uniq -cAffiché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.
Une erreur fréquente
Attention
On croit souvent que l’ordre du topic est l’ordre des faits. C’est l’ordre d’arrivée. Servez-vous du temps écrit dans chaque événement pour choisir sa fenêtre, et des décalages seulement pour dire ce que vous avez lu.
Un événement tardif arrive après un plus récent
Le café a été vendu à 58 secondes, mais il est arrivé après le lait vendu à 62. C’est un événement tardif : un événement plus récent est arrivé le premier.
Un vrai système ne peut pas attendre sans fin. Il ferme une fenêtre quand le temps le plus récent qu’il a vu dépasse sa fin. Une petite tolérance de retard garde la fenêtre ouverte un peu plus longtemps.
Trouver les événements tardifs
# Un événement est tardif si un événement plus récent est arrivé avant lui.
evenements = [[5, "pain"], [62, "lait"], [58, "cafe"], [125, "riz"], [70, "oeufs"]]
plus_recent = 0
for evenement in evenements:
if evenement[0] < plus_recent:
print(evenement[1], "est tardif : son temps", evenement[0], "est avant", plus_recent)
else:
plus_recent = evenement[0]
# Ajoutez [30, "the"] à la fin de evenements puis relancez.
Fermer une fenêtre après une tolérance
# Une fenêtre se ferme quand le temps le plus récent atteint sa fin plus la tolérance.
evenements = [[5, "pain"], [62, "lait"], [58, "cafe"], [125, "riz"], [70, "oeufs"]]
taille = 60
tolerance = 5
plus_recent = 0
compte = {}
abandonnes = []
for evenement in evenements:
debut = evenement[0] // taille * taille
if plus_recent >= debut + taille + tolerance:
abandonnes.append(evenement[1])
elif debut in compte:
compte[debut] = compte[debut] + 1
else:
compte[debut] = 1
if evenement[0] > plus_recent:
plus_recent = evenement[0]
print(compte, abandonnes)
# Mettez tolerance à 0, puis à 10, et relancez.
Envoyer une vente de plus, très tardive
curl -s -X POST -H "Content-Type: application/json" -d "{\"partition\":0,\"key\":\"caisse\",\"value\":\"30 the\",\"headers\":{},\"keySerde\":\"String\",\"valueSerde\":\"String\"}" http://kafka-ui:8080/api/clusters/lab/topics/caisses/messages -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.
Recompter les fenêtres
curl -s -N "http://kafka-ui:8080/api/clusters/lab/topics/caisses/messages/v2?seekType=BEGINNING&limit=10" | grep -o '"value":"[^"]*"' | cut -d'"' -f4 | while read t article; do echo $((t / 60)); done | sort -n | uniq -cAffiché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.
Pour aller plus loin : choisir une tolérance
Relancez le code de tolérance avec 0, 5 puis 10. Notez combien d’événements chacune abandonne.
Répondez ensuite en une phrase : un bilan de caisse pour le directeur en fin de journée, et une alarme qui doit sonner en quelques secondes. Lequel peut attendre les événements tardifs, et pourquoi ?