Tam bir kez vs En az bir kez
1) Anlambilimi bile neden tartışıyor
Teslimat semantiği, alıcının çökme ve geri çekilme sırasında mesajı ne sıklıkta göreceğini belirler:- En fazla bir kez - tekrarlama olmadan, ancak kayıp mümkündür (nadiren kabul edilebilir).
- En az bir kez - kaybetmeyin, ancak kopyalar mümkündür (çoğu broker/kuyruğun varsayılanı).
- Tam olarak bir kez - her mesaj, gözlemlenen etki açısından tam olarak bir kez işlenir.
Anahtar gerçek: Küresel işlemlerin ve eşzamanlı tutarlılığın olmadığı dağıtılmış bir dünyada, "temiz'bir uçtan uca tam bir kez ulaşılamaz. Tam olarak bir kez etkili bir şekilde inşa ediyoruz: taşımada tekrarlara izin veriyoruz, ancak işlemeyi idempotent hale getiriyoruz, böylece gözlemlenen etki'bir kez gibi ".
2) Arıza deseni ve kopyaların meydana geldiği yer
Tekrarları nedeniyle görünür:- Kayıplar ack/commit (üretici/broker/tüketici "duymadı" onayı).
- Liderlerin/kopyaların yeniden seçilmesi, ağ koptuktan sonra geri kazanımlar.
- Herhangi bir alanda zaman aşımları/geri çekilmeler (kliyent, broker, konsyumer, lavabo).
Sonuç: Taşımacılığın "teslimatının benzersizliğine" güvenemezsiniz. Etkileri yönetme: veritabanına yazma, para borçlandırma, mektup gönderme vb.
3) Sağlayıcılarda tam olarak bir kez ve gerçekte ne olduğu
3. 1 Kafka
Tuğla verir:- Idempotent Producer ('etkinleştir. Idotence = true ') - geri çekilirken üretici tarafında kopyaları önler.
- İşlemler - atomik olarak mesajları birkaç grup halinde yayınlar ve tüketim ofsetlerini ("boşluklar" olmadan okuma-süreç-yazma modeli) gerçekleştirir.
- Sıkıştırma - son değeri anahtara göre depolar.
Ancak "zincirin sonu" (lavabo: DB/ödeme/posta) hala idempotency gerektirir. Aksi takdirde, işleyicinin çift etkisi iki katına neden olur.
3. 2 NATS/Tavşan/SQS
Varsayılan, ack/redelivery ile en az bir keredir. Uygulama düzeyinde tam olarak bir kez elde edilir: anahtarlar, deadstore, upsert.
Sonuç: Tam olarak bir kez taşıma ≠ tam olarak bir kez etkisi. İkincisi işleyicide yapılır.
4) En az bir kez üzerinde tam olarak bir kez etkili bir şekilde nasıl inşa edilir
4. 1 Idempotency anahtarı
Her komut/olay doğal bir anahtar taşır: 'payment _ id', 'order _ id # step', 'saga _ id # n'. İşleyici:- Çekler "zaten görüldü mü?" - TTL/Retsch ile Dedup-stor (Redis/DB).
- Gördüyseniz, önceden hesaplanan sonucu tekrarlar veya işlem yapmaz.
lua
-- SET key if not exists; expires in 24h local ok = redis.call("SET", KEYS[1], ARGV[1], "NX", "EX", 86400)
if ok then return "PROCESS" else return "SKIP" end
4. 2 Tabanda Uppert (idempotent cink)
Girişler UPSERT/ON CONFLICT ile sürüm/miktar kontrolü ile yapılır.
PostgreSQL:sql
INSERT INTO payments(id, status, amount, updated_at)
VALUES ($1, $2, $3, now())
ON CONFLICT (id) DO UPDATE
SET status = EXCLUDED.status,
updated_at = now()
WHERE payments.status <> EXCLUDED.status;
4. 3 İşlemsel Giden Kutusu/Gelen Kutusu
Outbox: Bir ticari işlem ve bir olay-yayınlama girişi aynı veritabanı işleminde gerçekleşir. Arka plan yayıncısı giden kutusunu okur ve aracıya gönderir - devlet ile olay arasında bir tutarsızlık yoktur.
Gelen kutusu: gelen komutlar için, 'message _ id've yürütmeden önce sonucu kaydedin; Yeniden işleme kaydı görür ve yan etkileri tekrarlamaz.
4. 4 Tutarlı zincir işleme (okuma - süreç - yazma)
Kafka: işlem bir atom bloğunda "ofset oku - taahhüt sonuçlarını yazdı".
İşlemler olmadan:'önce sonucu/Gelen kutusunu yazın, sonra ack "; Çökme ile, yinelenen Gelen Kutusu'nu görecek ve no-op ile bitecektir.
4. 5 SAGA/ofsetler
Idempotency imkansız olduğunda (harici sağlayıcı parayı yazdı), telafi edici işlemleri (geri ödeme/geçersiz) ve idempotent harici API'leri (aynı 'Idempotency-Key'ile tekrarlanan' POST 'aynı sonucu verir) kullanırız.
5) En az bir kez yeterli olduğunda
Anahtar tabanlı sıkıştırma ile önbellek/maddeleştirilmiş görünümlerin güncelleştirilmesi.
Yeniden artırmanın kabul edilebilir olduğu sayaçlar/metrikler (veya sürümle deltaları depolayın).
İkincil harfin kritik olmadığı bildirimler (yine de bir anahtar koymak daha iyidir).
Kural: eğer çift iş anlamını değiştirmezse veya kolayca bulabilirsek - en az bir kez + kısmi koruma.
6) Performans ve maliyet
Tam olarak bir kez (hatta "etkili'bir şekilde) daha pahalıya mal olur: ek kayıtlar (Gelen Kutusu/Giden Kutusu), anahtarların saklanması, işlemler, tanılama daha zordur.
En az bir kez daha ucuz/daha basit, verim/p99'da daha iyidir.
Değerlendir: Çifte fiyat × çifte olasılık vs koruma maliyeti.
7) Örnek yapılandırmalar ve kod
7. 1 Kafka üreticisi (idempotence + işlemler)
properties enable.idempotence=true acks=all retries=INT_MAX max.in.flight.requests.per.connection=5 transactional.id=orders-writer-1
java producer.initTransactions();
producer.beginTransaction();
producer.send(recordA);
producer.send(recordB);
// также можно atomically commit consumer offsets producer.commitTransaction();
7. 2 Gelen kutusu konsolu (sözde kod)
pseudo if (inbox.exists(msg.id)) return inbox.result(msg.id)
begin tx if!inbox.insert(msg.id) then return inbox.result(msg.id)
result = handle(msg)
sink.upsert(result) # идемпотентный синк inbox.set_result(msg.id, result)
commit ack(msg)
7. 3 HTTP Idempotency-Key (harici API'ler)
POST /payments
Idempotency-Key: 7f1c-42-...
Body: { "payment_id": "p-123", "amount": 10.00 }
Aynı anahtarla tekrarlanan POST - aynı sonuç/durum.
8) Gözlemlenebilirlik ve metrikler
'duplicate _ attempts _ total' - kaç kez bir çift yakalandı (Inbox/Redis'e göre).
'empotency _ hit _ rate' - idempotency tarafından "kaydedilen" tekrarların oranı.
'tn _ abort _ rate' (Kafka/DB) - geri dönüşlerin payı.
'outbox _ backlog' - yayın gecikmesi.
'exactly _ once _ path _ latency {p95, p99}' vs'en az _ bir kez _ path _ latency '- overhead.
Denetim günlükleri: bir grup 'message _ id', 'idempotency _ key', 'saga _ id', 'girişim'.
9) Test oyun kitapları (Oyun Günleri)
Tekrarını gönder: yapay zaman aşımları ile üretici retrays.
"Lavabo ve ack" arasındaki çarpışma: Gelen Kutusu/Upsert'in çift olmasını önlediğinden emin olun.
Yeniden teslimat: komisyoncuda yeniden teslimatı artırmak; Dedup'ı kontrol et.
Harici API'lerin idempotensi: Aynı anahtarla tekrarlanan POST aynı cevaptır.
Lead Change/Network Break: Kafka İşlemleri/Tüketici Davranışlarını Kontrol Edin.
10) Anti-desenler
Ulaşıma güvenin: "Kafka'ya tam olarak bir kez sahibiz, böylece anahtarsız yapabilirsiniz" - hayır.
Kayıt öncesi No-op ack: akkled ama lavabo düştü - kayıp.
DLQ/jitter geri çekilme eksikliği: sonsuz tekrarlar ve fırtına.
Doğal anahtarlar yerine rastgele UUID'ler: tekilleştirilecek hiçbir şey yok.
Gelen Kutusu/Giden Kutusu'nu indekssiz üretim tablolarıyla karıştırma: sıcak kilitler ve p99 kuyrukları.
Dış sağlayıcılarda idempotent API olmadan ticari işlemler.
11) Seçim kontrol listesi
1. Çift fiyat (para/yasal/UX) vs koruma fiyatı (gecikme/karmaşıklık/maliyet).
2. Doğal olay/operasyon anahtarı var mı? Değilse, istikrarlı bir tane bulun.
3. Lavabo Upsert/versioning'i destekliyor mu? Aksi takdirde - Gelen kutusu + tazminat.
4. Global işlemlere mi ihtiyacınız var? Değilse, SAGA'ya bölün.
5. Tekrar oynatmaya/uzun süre tutmaya mı ihtiyacınız var? Kafka + Çıkış Kutusu. Hızlı RPC/düşük gecikme süresine mi ihtiyacınız var? NATS + Idempotency-Key.
6. Çok kiracılık ve kotalar: anahtar/alan izolasyonu.
7. Gözlemlenebilirlik: Idempotency ve backlog metrikleri dahil edilmiştir.
12) SSS
S: "Matematiksel" tam olarak bir kez uçtan uca ulaşmak mümkün mü?
C: Sadece tek bir tutarlı mağaza ve işlemlere sahip dar senaryolarda. Genel olarak hayır; tam olarak-bir kez idempotency aracılığıyla etkili kullanın.
S: Hangisi daha hızlı?
A: En azından bir kez. Tam olarak bir kez, p99 ve maliyetin üzerindeki işlemleri/anahtar depolamasını ekler.
S: Idempotence anahtarları nerede saklanır?
C: TTL ile hızlı durdurma (Redis) veya Gelen Kutusu tablosu (PK = message _ id). Ödemeler için - daha uzun (gün/hafta).
S: TTL dedup anahtarları nasıl seçilir?
A: Minimum = maksimum yeniden teslimat süresi + operasyonel marj (genellikle 24-72 saat). Finans için - daha fazla.
S: Kafka'da tuşa göre sıkıştırma varsa anahtara ihtiyacım var mı?
A: Evet. Sıkıştırma depolamayı azaltır, ancak senkronizasyonunuzu idempotent yapmaz.
13) Toplam
En az bir kez - temel, güvenilir ulaşım semantiği.
İşlemci düzeyinde bir iş etkisi tam olarak bir kez elde edilir: Idempotency-Key, Inbox/Outbox, Upsert/versions, SAGA/compensation.
Seçim, maliyet ↔ tekrarlama riski ↔ kullanım kolaylığından ödün vermektir. Doğal anahtarlar tasarlayın, çürükleri idempotent yapın, gözlemlenebilirlik ekleyin ve düzenli olarak oyun günleri oynayın - o zaman boru hatlarınız retras ve başarısızlık fırtınasında bile öngörülebilir ve güvenli olacaktır.