Olay veri tekilleştirme
1) Neden veri tekilleştirme
Kopyalar, retray'ler, ağ zaman aşımları, yük devretme ve geçmiş verilerin yeniden oynatılması nedeniyle ortaya çıkar. Eğer kontrol edilmezse:- Değişmezler ihlal edilir (çift borçlar, tekrarlanan e-posta/SMS, "iki kez oluşturulmuş" sipariş);
- Maliyet artışı (yeniden yazma/yeniden işleme)
- çarpık analitik.
Veri tekilleştirmenin amacı, genellikle idempotency ile birlikte kabul edilebilir taşıma tekrarları ile bir kerelik gözlemlenen bir etki sağlamaktır.
2) Veri tekilleştirme nereye yerleştirilir (katmanlar)
1. Edge/API ağ geçidi - 'Idempotency-Keu'/body + imzası ile açık kopyaları kesin.
2. Broker/stream - anahtar/sıra ile mantıksal veri tekilleştirme, bir ıskalamada birleştirme (daha az sıklıkla - maliyet nedeniyle).
3. Olay alıcısı (tüketici) - ana konum: Gelen kutusu/anahtar tablosu/önbellek.
4. Lavabo (DB/önbellek) - benzersiz anahtarlar/UPSERT/sürümler/sıkıştırma.
5. ETL/analiz - zaman penceresine göre son tarih ve sütun yataklarındaki anahtar.
Kural: Mümkün olduğunca erken, ancak yanlış pozitiflerin maliyetini ve tekrar oynatma ihtiyacını dikkate alarak.
3) Veri tekilleştirme anahtarları
3. 1 Doğal (tercih edilen)
'Payment _ id', 'order _ id', 'saga _ id # step', 'aggregate _ id # seq'.
Stabiliteyi ve anlamı garanti eder.
3. 2 Kompozit
'(tenant_id, type, external_id, version)' или '(user_id, event_ts_truncated, payload_hash)'
3. 3 Parmak izi
Alanların deterministik bir alt kümesinin karma (normalize düzen/kayıtlar), isteğe bağlı olarak 'HMAC (gizli, yük)'.
3. 4 Diziler/Sürümler
Toplam başına monoton 'seq' (iyimser engelleme/sürüm oluşturma).
Anti-pattern: Bir işletme ile bağlantısı olmayan "rastgele UUID" imkansızdır.
4) Zaman pencereleri ve sipariş
Veri tekilleştirme penceresi - etkinliğin tekrar gelebileceği süre (genellikle 24-72 saat; Finans için - daha uzun).
Sıra dışı: Geç kalalım. Akış çerçevelerinde - etkinlik zamanı + filigranlar.
Sürgülü/Fix-pencere deadup: "Son N dakika içinde anahtarı gördünüz mü? ».
Sıra farkındalığı: eğer 'seq' son işleme ≤ - çift/tekrar.
5) Veri yapıları ve uygulamaları
5. 1 Tam muhasebe
Redis SET/STRING + TTL: 'SETNX key 1 EX 86400' -'ilk kez - işliyoruz, aksi takdirde - SKIP ".
LRU/LFU önbellek (in-proc): hızlı, ancak uçucu - sadece ilk engel olarak daha iyi.
SQL benzersiz indeksleri + UPPERT: "insert or update" (idempotent effect).
5. 2 Yaklaşık yapılar (olasılıksal)
Bloom/Cuckoo filtresi: ucuz bellek, yanlış pozitifler mümkündür. Finans/siparişler için değil, bariz bir "gürültülü" düşüş (örneğin, telemetri) için uygundur.
Count-Min Sketch: "Sıcak" çekimlere karşı korumak için frekansları tahmin etmek.
5. 3 Akış durumları
Kafka Streams/Flink: TTL ile anahtarlı hal mağazası, pencerede anahtarla dedup; Kontrol noktası/geri yükleme.
Filigran + izin verilen gecikme: Geç olaylar penceresini yönetir.
6) İşlemsel desenler
6. 1 Gelen Kutusu (gelen tablo)
'Message _ id'/tuşunu kaydedin ve yan etkilere neden olun: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;
Tekrar oynatma kaydı görür ve efekti tekrarlamaz.
6. 2 Çıkış Kutusu
Bir işlemde iş kaydı ve olay - yayıncı komisyoncuya gönderir. Çifte tüketiciyi ortadan kaldırmaz, ancak "delikleri" hariç tutar.
6. 3 Benzersiz Dizinler/UPPERT
sql
INSERT INTO payments(id, status, amount)
VALUES ($1, $2, $3)
ON CONFLICT (id) DO NOTHING; -- "create once"
veya kontrollü sürüm yükseltme:
sql
UPDATE orders
SET status = $new, version = version + 1
WHERE id=$id AND version = $expected; -- optimistic blocking
6. 4 Agregaların sürümleri
Event if 'event geçerlidir. sürüm = toplam. sürüm + 1 '. Aksi takdirde - çift/tekrar/çatışma.
7) Deadup ve komisyoncular/akışlar
7. 1 Kafka
Idempotent Producer giriş çiftlerini azaltır.
İşlemler atomik olarak ofset + çıktı kayıtlarını işlemenizi sağlar.
Sıkıştırma: anahtar başına son değeri saklar - post-factum dedup/coalescing (ödemeler için değil).
Tüketici tarafı: Pencere anahtarları için eyalet mağazası/Redis/DB.
7. 2 NATS/JetStream
Ack/redelivery - en az bir kez. Tüketicide Dedup (Gelen Kutusu/Redis).
JetStream dizisi/tüketici çalışması tekrarları tanımlamayı kolaylaştırır.
7. 3 Kuyruk (Tavşan/SQS)
Görünürlük zaman aşımı + tekrarlanan teslimatlar - bir anahtar + deadstore'a ihtiyacınız var.
SQS FIFO, 'MessageGroupId'/' DeduplicationId'ile yardımcı olur, ancak TTL pencereleri sağlayıcı tarafından sınırlıdır - iş gerektiriyorsa anahtarları daha uzun süre saklayın.
8) Depolama ve analizörler
8. 1 ClickHouse/BigQuery
Pencere ile Dedup: 'ORDER BY key, ts've' argMax'/' any 'Last' koşullu.
ClickHouse:sql
SELECT key,
anyLast(value) AS v
FROM t
WHERE ts >= now() - INTERVAL 1 DAY
GROUP BY key;
Veya "benzersiz" olayların maddeleşmiş bir katmanı (anahtar/sürüm ile birleştirme).
8. 2 Günlükleri/telemetri
Diyelim ki yaklaşık-dump (Bloom) üzerinde ingest> save network/disk.
9) Yeniden işleme, tekrar oynatma ve geri doldurma
Dedup tuşları tekrar oynatmada hayatta kalmalıdır (TTL ≥ tekrar penceresi).
Geri doldurma için, anahtar alanını sürümle birlikte kullanın ('anahtar # kaynak = batch2025') veya çevrimiçi pencereye müdahale etmemek için "sızıntıları" ayırın.
Sonuç artefaktlarını saklayın (hash/version) - bu, tekrarlarda "hızlı atlamayı" hızlandırır.
10) Metrikler ve gözlemlenebilirlik
'dedup _ hit _ total'/' dedup _ hit _ rate' - yakalanan kopyaların oranı.
Olasılıksal filtreler için 'dedup _ fp _ rate'.
'window _ size _ seconds' actual (geç gelen telemetri ile).
'inbox _ conflict _ total', 'upsert _ conflict _ total'.
'yeniden oynatılmış _ olaylar _ toplam', 'atlanmış _ by _ inbox _ toplam'.
Kiracı/anahtar/türe göre profiller: En çok nerede alınır ve neden.
Логи: 'message _ id', 'idempotency _ key', 'seq', 'window _ id','action = process 'skip'.
11) Güvenlik ve gizlilik
PII'yi anahtara koymayın; Özet/diğer ad kullanın.
Parmak izini imzalamak için - HMAC (gizli, canonical_payload) çarpışmaları/sahteciliği önlemek için.
Anahtarların depolama süresini uyumlulukla koordine edin (GDPR saklama).
12) Performans ve maliyet
In-proc LRU ≪ Redis, SQL'i işlem başına gecikme/maliyetle ≪.
Redis: ucuz ve hızlı, ancak anahtarların ve TTL'nin hacmini düşünün; 'kiracı/hash'tarafından shardy.
SQL: p99 tarafından pahalı, ancak güçlü garantiler ve kitle sağlar.
Olasılıksal filtreler: çok ucuz, ancak FP'ler mümkündür - "ekstra SKIP'in kritik olmadığı yerlerde kullanın.
13) Anti-desenler
"Kafka'ya tam olarak bir kez sahibiz - anahtara gerek yok. "Gerekli - bir çürük/iş katmanında.
Anahtarlar için çok kısa TTL - tekrarlar/gecikme bir çift sağlayacaktır.
Global tek dedup - hotspot ve SPOF; kiracı/anahtar tarafından paylaşılmaz.
Dedup sadece bellekte - süreç kaybı = alma dalgası.
Para/emirler için Bloom - yanlış pozitif meşru operasyonu mahrum edecek.
Tutarsız yük kanonizasyonu - anlam bakımından aynı olan mesajlar için farklı karmalar.
Sıra dışı yoksayma - geç olaylar hatalı olarak kopyalarla işaretlenir.
14) Uygulama kontrol listesi
- Doğal bir anahtar (veya bileşik/parmak izi) tanımlayın.
- Dedup penceresini ve 'gecikme' politikasını ayarlayın.
- Belirli seviye (ler): kenar, tüketici, lavabo; Parçalanmayı sağlar.
- Gelen Kutusu/UPSERT'i uygulayın; Akışlar için - anahtarlı durum + TTL.
- Yaklaşık bir bariyere ihtiyacınız varsa - Bloom/Cuckoo (sadece kritik olmayan alanlar için).
- Yeniden oynatma uyumluluğunu yapılandırın (TTL ≥ yeniden oynatma/geri doldurma penceresi).
- Metrikler 'dedup _ hit _ rate', çakışmalar ve pencere gecikmeleri; kiracı başına gösterge panoları.
- Oyun Günü: zaman aşımları/yeniden oynatmalar, tekrar oynatma, sıra dışı, önbellek düşüşü.
- Belge yükü kanonizasyonu ve anahtar sürüm oluşturma.
- Sıcak tuşlar ve uzun pencereler üzerinde yük testleri yapın.
15) Örnek Yapılandırmalar/Kod
15. 1 Redis SETNX + TTL (bariyer)
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 Gelen Kutusu
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
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 (anahtarlı durum + TTL, sözde)
java
ValueState<Boolean> seen;
env. enableCheckpointing(10000);
onEvent(e):
if (!seen.value()) { process(e); seen. update(true); }
15. 5 NGINX/API ağ geçidi (Kenar üzerinde Idempotency-Key)
nginx map $http_idempotency_key $idkey { default ""; }
Proxy the key to the backend; backend solves deadup (Inbox/Redis).
16) SSS
S: Ne seçmeli: deadup mu yoksa saf idempotans mı?
C: Genellikle her ikisi de: deadup hızlı bir "filtre" (tasarruf), idempotans doğru etkinin garantisidir.
S: Hangi TTL koymak için?
A: ≥ maksimum olası yeniden teslimat süresi + envanter. Tipik olarak 24-72 saat; Finans ve ertelenmiş görevler için - günler/haftalar.
S: Geç olayları nasıl ele alıyorsunuz?
A: 'İzin verilen gecikme've alarm' late _ event 'yapılandırın; Daha sonra olanlar - ayrı bir dal aracılığıyla (yeniden hesaplama/atlama).
S: Tüm telemetri akışı tekilleştirilebilir mi?
C: Evet, yaklaşık filtreler (Bloom) kenarda, ancak FP'yi göz önünde bulundurun ve kritik iş etkileri için geçerli değildir.
S: Deadup geri doldurma yoluna mı giriyor?
C: Anahtar boşluklarını ayırın ('anahtar # batch2025') veya geri doldurma süresi boyunca bariyeri devre dışı bırakın; TTL anahtarları yalnızca çevrimiçi pencereleri kapsamalıdır.
17) Toplam
Veri tekilleştirme kompozisyondur: doğru anahtar, pencere ve durum yapısı + işlem desenleri (Gelen Kutusu/Giden Kutusu/UPSERT) ve sipariş ve geç olayların dikkatli bir şekilde ele alınması. Engelleri en ucuz olduğu yere yerleştirin, çürüklerde idempotans sağlayın, 'dedup _ hit _ rate' ölçün ve tekrarları/başarısızlıkları test edin - bu şekilde gereksiz gecikme ve maliyet kuyrukları olmadan "etkili bir şekilde tam olarak bir kez" elde edersiniz.