Tam olarak bir kez semantik
Tam olarak ne-bir kez gerçekten
"Tam olarak bir kez" genellikle iki farklı şey anlamına gelir:- Teslimat: Mesaj tüketiciye tam olarak bir kez teslim edilecektir.
- İşleme: Son yan etki (veritabanına yazma, bakiyeyi değiştirme, başka bir olay yayınlama), daha fazla teslimat veya deneme olsa bile, tam olarak bir kez gerçekleşecektir.
Dağıtılmış sistemlerde, semantik işleme hakkında konuşmak daha güvenilirdir. Tam olarak bir kez teslimat zordur (kopyalar ve kopyalar kaçınılmazdır), ancak ortaya çıkan durum tek bir işleme eşdeğer olarak yapılabilir.
EOS gerekli olduğunda ve olmadığında
Aşağıdaki durumlarda EOS gereklidir:- Nakit işlemler ve bakiyeler: Çift yazıya izin verilmez.
- Lisans/kota muhasebesi, fatura sayaçları.
- Geri dönüşü olmayan harici çağrılar (örneğin, bir kerelik anahtar aktivasyonu).
- Etkiler geri dönüşümlü veya telafi edilebilir (sagalar, dönüşler).
- Geçici kopyalara vitrinlerde/günlüklerde izin verilir.
- Bir idempotent lavabo sağlamak, tüm yol boyunca işlemleri sürüklemekten daha ucuzdur.
Model: Uçtan uca vs. Hop-by-hop
Hop-by-hop EOS: Her bir bölüm (kaynak, işlemci, alıcı) eylemini tam olarak bir kez uygulayacağını garanti eder.
Uçtan uca EOS: Tüm zincir, "gerçek'ten" yan etki'ye kadar, sonucun tek bir tedaviye eşdeğer olmasını sağlar.
Pratikte, uçtan uca, her atlamada işlemlerin ve/veya idempotency'nin bir kombinasyonu ile elde edilir.
Temel yapı taşları
1. Idempotent işlemleri
İşlem tuşunda aynı sorguyu tekrarlamak aynı sonucu verir.
Ключи: 'idempotency _ key'/' event _ id'/' operation _ id'.
Uygulama: TTL ile "görülen" işlemlerin tablosu ≥ giriş günlüğünün sunumu.
2. Read-process-write işlemleri
Bir atomik iş biriminde, hem yan etki hem de okuma ilerlemesi (ofsetler/pozisyon) kaydedilir. Bu, adımlar arasında düşerken "hayaletleri" ortadan kaldırır.
3. Sürüm Oluşturma/SEKANS
Agrega için bir sürüm/sayaç saklanır; Değişiklikler yalnızca 'expected _ version' eşleşirse geçerlidir. Aynı olayın tekrarları, bir kez sürüm efektini artırmaz.
4. Veri tekilleştirme
'(consumer_id, event_id)' veya işlemin doğal 'business _ id' üzerindeki dizin.
Uygulama kalıpları
1) Ofset fiksasyonlu işlem günlüğü + işlem lavabosu
Akış işleme için idealdir.
Günlükten okuyoruz (sadece onaylanmış girişler).
İşlem yapıyoruz.
- a) lavaboya efekti yazma (veritabanı/tablo),
- b) "read to offset N" düzeltmesi (aynı veritabanında).
- Taahhüt et. Yeniden başlatırken, ya her şey indirgenir (ve ofset kaydırılır) ya da hiçbir şey.
Özellikler: tekrarlanan yürütme zararlı değildir; "Tam olarak bir kez", mesaj iki kez okunmuş olsa bile.
2) Outbox + idempotent tüketici
İşlemsel üretici hizmetleri için.
Bir veritabanı işleminde: etki alanı kaydını değiştirin ve olayı giden kutusuna yazın.
Tekrarlayıcı, olayı aynı 'event _ id'ile otobüse iletir.
Tüketiciler olayları idempotently olarak uygular ('event _ id'ile dedup).
Özellikler: Üretici hiçbir gerçeğin kaybolmamasını sağlar; Tüketiciler tam olarak bir etki garanti eder.
3) Kafka/Flink benzeri sistemlerde EOS (kavramsal olarak)
Idempotent üreticisi: geri çekilme göndermeye karşı korur.
Üretici işlemleri: Konulardaki bir grup giriş + bir tüketim vardiyası atomik olarak işlenir; Okuyucular 'read _ committed' izolasyonunu kullanır.
İşlem tarafı devlet deposunu depolar ve işlemle birlikte taahhüt eder.
Özellikler: Mağaza/sürüklemeye yeniden başlamak çift etkiye yol açmaz; Akış yönünde "görünmeyen" kopyalar.
4) Idempotent "lavabolar" uppert/birleştirme yoluyla
Lavabo 'operation _ id'/' event _ id' alır ve 'UPPERT... OLMAYAN YERDE '.
Yan etki (örneğin, tahakkuk) "henüz uygulanmadı" kontrolü ile atomik olarak gerçekleştirilir.
Özellikler: Ucuz EOS yöntemi, dağıtılmış işlemler olmadan, depolama ile kenarında.
Temel uygulama detayları
İşlem kimlikleri
Tekrarlar için deterministik olmalıdır (geri çekilirken yeni bir UUID oluşturmayın).
Sabit bir kapsama sahip olmak (tüketici/birim/sistem üzerinde).
Veri tekilleştirme tablosu
Колонки: 'consumer _ id', 'operation _ id', 'applied _ at','tl _ expires _ at '.
Dizinler üzerinde '(consumer_id, operation_id)'.
TTL maksimum tekrar penceresini ≥ (günlük tutma + olası gecikmeler).
Iyimser rekabet
Yazma modelinde, ünitenin sürümünü saklayın.
Bir olay/komut uygularken, 'WHERE version =: expected' kullanın; Duplicate sürümü artırmaz.
Sipariş/Sipariş
EOS "tam olarak aynı sipariş" değildir. "Toplu iş anahtarı (tüm toplu olaylar - bir toplu iş) ve/veya 'eşitlik' karşılaştırması ile tutarlılık sağlayın.
Idempotent harici aramalar
Güvenli olmayan yöntemler için (örneğin, bir üçüncü taraf hizmetine HTTP web kitapları), 'Idempotency-Key' ekleyin ve iş ortağının bunu desteklemesini isteyin.
Sık bindirmeler
EOS tek bir yerde: eğer lavabo idempotent ise, ancak idempotency olmadan ikincil olaylar yayarsanız, aşağı yönde "tam olarak birçok kez" alırsınız.
İki taahhüt: önce veritabanında, sonra brokerda ofset taahhüt - aralarındaki düşüş yinelenen etkiler yaratır.
Ham CDC'ler dışarı: DB şemasını değiştirmek tüketici idempotensisini kırar.
Kararsız tuşlar: 'operation _ id' zamana/rasgele ve yeniden oynatma sırasında değişikliklere bağlıdır.
Maliyet ve takaslar
Gecikme: işlemler/izole edilmiş okumalar - p95/p99 büyüme.
Genel depolama: veri tekilleştirme tabloları, durum depoları, işlem günlükleri.
Operasyonel karmaşıklık: işlem zaman aşımları, iş parçacığının yeniden dengelenmesi, sıkışmış oturumlar.
Tanılama: daha fazla durum ("kamit", "görünür" read_committed, "geri sarılmış").
EOS noktasını seçin: kritik toplamlar ve efektler için; Geri kalanını idempotency ve tazminat ile örtün.
Tam olarak-bir kez test etme
1. Hata enjeksiyonu: "Etkiyi kaydetti've" ofseti kaydetti "adımları arasındaki işlemdeki düşüş.
2. Kopyalar: Aynı mesajı 2-5 kez indirin, bir efektten emin olun.
3. Yeniden başlatmalar ve yeniden dengelemeler: işçilerin durdurulması/yeniden başlatılması, çift işlemenin yokluğunu kontrol edin.
4. Ağ kanatçıkları: orta işlem zaman aşımları, yeniden deneme yapın.
5. Yük testleri: kuyruk büyümesi - "işlemde sonsuza dek" için bir bozulma olup olmadığı.
Mini Şablonlar (Sözde)
Ofset sabitleme ile idempotent lavabo
pseudo begin tx if not exists(select 1 from dedup where consumer_id=:c and op_id=:id)
then apply_effect(...) -- upsert / merge / add_one_time_action insert into dedup(c, id, applied_at) values(:c,:id, now)
end if update offsets set pos=:pos where consumer_id=:c commit
Birim sürümü ile komut
pseudo begin tx update account set balance = balance +:delta,
version = version + 1 where id=:account_id and version=:expected_version;
if row_count=0 then error CONCURRENT_MODIFICATION commit
Güvenlik ve uyumluluk
Veri tekilleştirme tablolarında PII/PCI: minimum depolama, ham veri yerine belirteçler kullanın.
Denetim: log 'operation _ id', 'trace _ id', sonuç (APPLIED/ALREADY_APPLIED).
Depolama politikası: Dedup tablolarında TTL, ofsetlerin/günlüklerin arşivlenmesi.
Anti-desenler
"Gerçek tam bir kez teslimat": Etki idempotensi olmadan taşıma protokolü düzeyinde kopyaları dışlama girişimi.
Her şey için küresel dağıtılmış işlemler: Tüm hizmetlerde XA/2PC kırılgan ve yavaştır.
Idempotent olmayan yan etkilerin karıştırılması (örneğin, ofset işlemeden önce gönderilen e-posta).
Çalışma anahtarlarının eksikliği: yükün "benzersizliğine" güvenmek.
Üretim kontrol listesi
- Her kritik etkinin bir idempotent anahtarı vardır.
- Ofset/okuma pozisyonu, etkili olan bir işlemde sabitlenir.
- Veri tekilleştirme tabloları indekslenir; TTL ≥ log tutma.
- Kümeler için iyimser rekabet (sürüm/dizi) etkinleştirilmiştir.
- Konular/Konular "Yalnızca Comp" modunda okunur (varsa).
- Kopya ve düşme testleri CI/CD'de mevcuttur.
- Gösterge tabloları: tekrarların paylaşımı, başarısız işlemler, engelleme süresi, gecikmeler.
- 'Idempotency-Key'/yeniden denemeler/zaman aşımları için entegratör belgeleri.
SSS
İşlemler olmadan EOS sağlanabilir mi?
Genellikle evet - lavabonun idempotensi (uppert/merge) ve agregaların sürümlenmesi yoluyla. İşlemler garantileri basitleştirir ancak maliyeti artırır.
Herkesin tam olarak bir kez ihtiyacı var mı?
Hayır. Çok pahalı. Tazminatın mümkün olmadığı/pahalı olmadığı yerlerde puan uygulayın.
Mektuplar/webhook'lar EOS ile nasıl ilişkilendirilir?
Taahhütten önce bildirimi tamponlayın, etkiyi düzelttikten sonra gönderin; 'notification _ id'yi saklayın ve idempotent göndermeyi yapın.
Hangisi daha önemli - teslimat mı yoksa işleme mi?
İşlem yapılıyor. Teslimatlar tekrarlanabilir; Son durum doğru ve tek olmalıdır.
Sonuç
Tam olarak bir kez, etkinin doğruluğu ile ilgilidir ve kablolamada kopyaların bulunmaması ile ilgili değildir. Idempotency, etkinin atomik fiksasyonu ve okuma ilerlemesi, makul bölümleme ve sürüm disiplini kombinasyonu ile elde edilir. Hata maliyetinin kabul edilemez olduğu yerlerde EOS uygulayın ve gerçekliğini düşmelerle ve testlerle test edin - ulaşıma inanmayın.