GH GambleHub

Déduplication des événements

1) Pourquoi la déduplication est nécessaire

Les doublons apparaissent à cause des retraits, des temporisations en ligne, des restaurations après les faux et de la réplication des données historiques. S'ils ne sont pas contrôlés :
  • les invariants sont perturbés (doubles prélèvements, réémail/SMS, ordre « double créé ») ;
  • les coûts augmentent (réenregistrement/traitement) ;
  • l'analyste est faussé.

L'objectif de la déduplication est de fournir un effet observé unique dans les répétitions de transport autorisées, souvent avec l'idempotence.

2) Où placer la déduplication (niveaux)

1. Passerelle Edge/API - Coupez les prises explicites selon 'Idempotency-Keu '/corps + signature.
2. Le courtier/stream est une déduplication logique par clé/séquencement, coalescing en cas d'échec (moins souvent en raison du coût).
3. Récepteur d'événements (consumer) - emplacement principal : Inbox/table de clés/cache.
4. Sink (OBD/cache) - clés uniques/UPSERT/version/compaction.
5. ETL/analyse est le dedup par la fenêtre temporelle et la clé dans les colonnes.

Règle : le plus tôt possible, mais en tenant compte du coût des faux positifs et de la nécessité d'un repli.

3) Clés de déduplication

3. 1 Naturel (de préférence)

`payment_id`, `order_id`, `saga_id#step`, `aggregate_id#seq`.
Ils garantissent stabilité et sens.

3. 2 Composés

`(tenant_id, type, external_id, version)` или `(user_id, event_ts_truncated, payload_hash)`.

3. 3 Empreintes (fingerprint)

Hash du sous-ensemble déterministe des champs (normaliser l'ordre/les registres), optionnellement 'HMAC (secret, payload)'.

3. 4 Séquences/versions

Monotone 'seq' per aggregate (blocage/versioning optimiste).

Anti-modèle : « UUID randomisé » sans lien avec l'entité commerciale - le dedup est impossible.

4) Fenêtres temporelles et ordre

La fenêtre de déduplication est la période pendant laquelle l'événement peut arriver à nouveau (généralement 24-72h ; pour la finance - plus longtemps).
Out-of-order : admettons le retard (lateness). Dans les cadres de streaming, event time + watermarks.
Sliding/Fix-window dedup : "Avez-vous vu la clé dans les dernières N minutes ? ».
Sequence-aware : si 'seq' ≤ le dernier traité, la prise/répétition.

5) Structures de données et implémentation

5. 1 Comptabilité exacte (exact)

Redis SET/STRING + TTL : 'SETNX key 1 EX 86400' → « pour la première fois - nous traitons, sinon - SKIP ».
Cache LRU/LFU (in-proc) : rapide mais volatile → mieux que la première barrière.
Index SQL unique + UPSERT : « insérer ou mettre à jour » (effet idempotent).

5. 2 Structures approximatives (probabilistic)

Bloom/Cuckoo filter : mémoire bon marché, faux positifs possibles (faux positif). Convient pour le drop « bruyant » explicite (par exemple, télémétrie), pas pour les finances/commandes.
Count-Min Sketch : estimation des fréquences pour la protection contre les prises « chaudes ».

5. 3 États de streaming

Kafka Streams/Flink : keyed state store avec TTL, dedup par clé dans la fenêtre ; checkpoint/restore.
Watermark + allowed lateness : gère la fenêtre des événements tardifs.

6) Modèles transactionnels

6. 1 Inbox (tableau entrant)

Nous gardons 'message _ id '/clé et le résultat jusqu'aux effets secondaires :
pseudo
BEGIN;
ins = INSERT INTO inbox(id, received_at) ON CONFLICT DO NOTHING;
IF ins_not_inserted THEN RETURN cached_result;
result = handle(event);
UPSERT sink with result; -- idempotent sync
UPDATE inbox SET status='done', result_hash=... WHERE id=...;
COMMIT;

La répétition verra l'enregistrement et ne répétera pas l'effet.

6. 2 Outbox

L'enregistrement d'entreprise et l'événement dans une transaction → le publieur donne au courtier. N'élimine pas la prise du consommateur, mais exclut les « trous ».

6. 3 Indices uniques/UPSERT

sql
INSERT INTO payments(id, status, amount)
VALUES ($1, $2, $3)
ON CONFLICT (id) DO NOTHING; -- "create once"
ou mise à jour contrôlée de la version :
sql
UPDATE orders
SET status = $new, version = version + 1
WHERE id=$id AND version = $expected; -- optimistic blocking

6. 4 Versionation des unités

L'événement est applicable si 'event. version = aggregate. version + 1`. Sinon, prise/répétition/conflit.

7) Dedup et courtiers/strim

7. 1 Kafka

Idempotent Producer réduit les prises à l'entrée.
Les transactions permettent de communiquer atomiquement les offsets + les enregistrements de sortie.
Compaction : stocke la dernière valeur de per key - dedup post-fact/coalesing (pas pour les paiements).
Consumer-side : state store/Redis/DB pour les clés de fenêtre.

7. 2 NATS / JetStream

Ack/rare → at-least-once. Dedup dans le consommateur (Inbox/Redis).
La séquence JetStream/Durabot du consommateur facilite l'identification des répétitions.

7. 3 Files d'attente (Rabbit/SQS)

Visibility timeout + redéploiements → besoin d'une clé + dedup store.
SQS FIFO avec 'MessageGroupId '/' DeduplicationId' aide, mais la fenêtre TTL est limitée par le fournisseur - gardez les clés plus longtemps si l'entreprise le demande.

8) Entrepôts et analyses

8. 1 ClickHouse/BigQuery

Dedup par fenêtre : 'ORDER BY key, ts'et' argMax '/' anyLast'avec condition.

ClickHouse:
sql
SELECT key,
anyLast(value) AS v
FROM t
WHERE ts >= now() - INTERVAL 1 DAY
GROUP BY key;

Ou une couche matérialisée d'événements « uniques » (merge par clé/version).

8. 2 Logs/télémétrie

Admettez approximate-dedup (Bloom) sur ingest → économisons le réseau/disque.

9) Traitement répété, repli et backfill

Les clés dedup doivent survivre à la réplication (TTL ≥ fenêtre de réplication).
Pour le backfill, utilisez l'espace clé avec la version ('key # source = batch2025') ou les « prunes » individuelles pour ne pas interférer avec la fenêtre en ligne.
Stockez les artefacts du résultat (hash/version) - cela accélère le « fast-skip » sur les répétitions.

10) Métriques et observabilité

« dedup _ hit _ total »/« dedup _ hit _ rate » est la proportion de prises.
'dedup _ fp _ rate' pour les filtres probabilistes.
'Window _ size _ second'est réel (par telemetry late arrivals).
`inbox_conflict_total`, `upsert_conflict_total`.
`replayed_events_total`, `skipped_by_inbox_total`.
Profils par tenant/key/type : où le plus de prises et pourquoi.

Логи: `message_id`, `idempotency_key`, `seq`, `window_id`, `action=process|skip`.

11) Sécurité et vie privée

Ne mettez pas le PII dans la clé ; utilisez des hashs/alias.
Pour la signature de l'empreinte - HMAC (secret, canonical_payload) pour éviter les conflits/contrefaçon.
Les durées de stockage des clés sont conformes à la conformité (GDPR restench).

12) Productivité et coût

In-proc LRU ≪ Redis ≪ SQL sur la latence/coût d'opération.
Redis : bon marché et rapide, mais tenir compte du volume des clés et du TTL ; Chardonnez par 'tenant/hash'.
SQL : cher par p99, mais donne de solides garanties et l'auditoire.
Filtres probabilistes : très bon marché, mais FP possible - appliquer là où le « SKIP superflu » n'est pas critique.

13) Anti-modèles

« Nous n'avons pas besoin de Kafka exactly-once ». J'ai besoin d'un bleu/business.
Un TTL trop court pour les clés → un relais/retard délivrera une prise.
Global One Dedup Store → hotspot et SPOF ; pas chardonné par tenant/clé.
Le dedup est seulement en mémoire - perte du processus = vague de prise.
Bloom pour l'argent/commandes - faux positif privera l'opération légitime.
La canonisation incohérente de payload - différents hachages sur identiques au sens de la communication.
Ignorer out-of-order - les événements tardifs sont marqués par des prises erronées.

14) Chèque de mise en œuvre

  • Identifiez la clé naturelle (ou composite/empreinte).
  • Définissez la fenêtre dedup et la stratégie « lateness ».
  • Sélectionnez le niveau (s) : edge, consumer, sink ; Prévoyez le chardon.
  • Implémenter Inbox/UPSERT ; pour les flux - keyed state + TTL.
  • Si vous avez besoin d'approximate-barrière est Bloom/Cuckoo (seulement pour les domaines non critiques).
  • Configurez la compatibilité de repli (TTL ≥ fenêtre de repli/backfill).
  • Métriques 'dedup _ hit _ rate', conflits et lagunes de fenêtres ; dashboards per-tenant.
  • Game Day : timeouts/retraits, replay, out-of-order, chute de cache.
  • Documenter la canonisation de payload et la versionation des clés.
  • Effectuer des tests de charge sur les « clés chaudes » et les fenêtres longues.

15) Exemples de configurations/codes

15. 1 Redis SETNX + TTL (barrière)

lua
-- KEYS[1] = "dedup:{tenant}:{key}"
-- ARGV[1] = ttl_seconds local ok = redis. call("SET", KEYS[1], "1", "NX", "EX", ARGV[1])
if ok then return "PROCESS"
else return "SKIP"
end

15. 2 PostgreSQL Inbox

sql
CREATE TABLE inbox (
id text PRIMARY KEY,
received_at timestamptz default now(),
status text default 'received',
result_hash text
);
-- In the handler: INSERT... ON CONFLICT DO NOTHING -> check, then UPSERT in blue.

15. 3 Kafka Streams (dedup dans la fenêtre)

java var deduped = input
.selectKey((k,v) -> v.idempotencyKey())
.groupByKey()
.windowedBy(TimeWindows. ofSizeWithNoGrace(Duration. ofHours(24)))
.reduce((oldV,newV) -> oldV)   // first wins
.toStream()
.map((wKey,val) -> KeyValue. pair(wKey. key(), val));

15. 4 Flink (state keyed + TTL, pseudo)

java
ValueState<Boolean> seen;
env. enableCheckpointing(10000);
onEvent(e):
if (!seen.value()) { process(e); seen. update(true); }

15. 5 passerelle NGINX/API (Idempotency-Key sur edge)

nginx map $http_idempotency_key $idkey { default ""; }
Proxy the key to the backend; backend solves deadup (Inbox/Redis).

16) FAQ

Q : Que choisir : dedup ou pure idempotence ?
R : En général, les deux : le dedup est un « filtre » rapide (économie), l'idempotence est la garantie d'un effet correct.

Q : Quel TTL mettre ?
R : ≥ le délai maximum de livraison éventuelle + stock. Typiquement 24-72h ; pour les finances et les tâches reportées - jours/semaines.

Q : Comment gérer les événements tardifs ?
A : Ajustez 'allowed lateness' et alarme 'late _ event' ; tardive - via une branche distincte (recompute/skip).

Q : Est-il possible de dédupliquer tout le flux de télémétrie ?
R : Oui, approximate-filtres (Bloom) sur edge, mais prendre en compte FP et ne pas appliquer aux effets critiques de l'entreprise.

Q : Le dedup interfère-t-il avec le backfill ?
R : Diviser les espaces clés ('key # batch2025') ou débrancher la barrière pendant le backfill ; Les clés TTL ne doivent couvrir que les fenêtres en ligne.

17) Résultats

La déduplication est une composition : la clé correcte, la fenêtre et la structure de l'état + les schémas transactionnels (Inbox/Outbox/UPSERT) et le travail éclairé avec l'ordre et les événements tardifs. Placez les barrières là où c'est le moins cher, assurez l'idempotentialité dans les bleus, mesurez 'dedup _ hit _ rate' et testez les relais/feels - de sorte que vous obtiendrez « effectivement exactly-once » sans trop de latence et de coût.

Contact

Prendre contact

Contactez-nous pour toute question ou demande d’assistance.Nous sommes toujours prêts à vous aider !

Commencer l’intégration

L’Email est obligatoire. Telegram ou WhatsApp — optionnels.

Votre nom optionnel
Email optionnel
Objet optionnel
Message optionnel
Telegram optionnel
@
Si vous indiquez Telegram — nous vous répondrons aussi là-bas.
WhatsApp optionnel
Format : +code pays et numéro (ex. +33XXXXXXXXX).

En cliquant sur ce bouton, vous acceptez le traitement de vos données.