Exactly-once vs At-least-once
1) Semantikani muhokama qilishning nima keragi bor?
Yetkazib berish semantikasi qabul qiluvchi xato va retrajlarda xabarni qanchalik tez-tez koʻrishini aniqlaydi:- At-most-once - takrorlamasdan, lekin yo’qotish mumkin (kamdan-kam hollarda qabul qilinadi).
- At-least-once - yo’qotmaymiz, lekin dublikatlar bo’lishi mumkin (ko’pgina brokerlar/navbatlarning defolti).
- Exactly-once - har bir xabar kuzatilgan ta’sir nuqtai nazaridan bir marta qayta ishlanadi.
Asosiy haqiqat: global tranzaksiyalar va sinxron muvofiqliksiz taqsimlangan dunyoda «sof» end-to-end exactly-once erishib bo’lmaydi. Biz exactly-once’ni samarali quramiz: transportda takrorlashga ruxsat beramiz, lekin idempotent bilan ishlov beramiz, shunda kuzatilayotgan ta’sir «xuddi bir marta» bo’ladi.
2) Rad etish modeli va dublikatlar qayerda paydo bo’ladi
Takrorlash quyidagilardan kelib chiqadi:- Yo’qotishlar ack/commit (prodyuser/broker/konsumer tasdiqlashni «eshitmadi»).
- Rahbarlarni/replikalarni qayta saylash, tarmoqdagi uzilishlardan keyin tiklash.
- Har qanday uchastkada taymautov/retraev (mijoz → broker → konsumer → sink).
Natijada, transportni «yetkazib berishning noyobligiga» tayanib boʻlmaydi. Biz effektlarni boshqaramiz: DBga yozish, pulni hisobdan chiqarish, xat jo’natish va boshqalar.
3) Etkazib beruvchilarda Exactly-once va bu aslida nima
3. 1 Kafka
Gʻishtlarni beradi:- Idempotent Producer (`enable. idempotence = true’) - retralarda prodyuser tomonidagi dubllarning oldini oladi.
- Tranzaksiyalar - bir nechta partiyalar va kommityat iste’mol ofsetlariga («o’tkazib yuborishsiz» read-process-write patterni) atomik ravishda xabarlarni e’lon qiladi.
- Compaction - oxirgi kalit qiymatini saqlaydi.
Ammo «zanjir oxiri» (sink: BD/to’lov/pochta) baribir idempotentlikni talab qiladi. Aks holda, ishlov beruvchining dubli effekt dublini keltirib chiqaradi.
3. 2 NATS / Rabbit / SQS
Andoza - ack/redelivery bilan at-least-once. Exactly-once dasturlar darajasida erishiladi: kalitlar, dedup-stor, upsert.
Xulosa: Exactly-once transporti ≠ exactly-once effekti. Oxirgisi ishlov beruvchida amalga oshiriladi.
4) At-least-once ustiga samarali exactly-once qurish
4. 1 Idempotent kaliti (idempotency key)
Har bir buyruq/hodisa tabiiy kalitga ega:’payment _ id’,’order _ id #step’,’saga _ id #n’. Ishlov beruvchi:- «Koʻrdingizmi?» - TTL/retenshnli dedup-stor (Redis/BD).
- Agar ko’rgan bo’lsangiz - ilgari hisoblab chiqilgan natijani takrorlaydi yoki no-op qiladi.
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 Upsert bazada (idempotent sink)
Yozuvlar UPSERT/ON CONFLICT orqali versiyani/summani tekshirish bilan amalga oshiriladi.
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 Tranzaksion Outbox/Inbox
Outbox: biznes-tranzaksiya va «nashr etish voqealari» yozuvi bitta DB tranzaksiyasida sodir bo’ladi. Orqa fon nashriyotchisi outbox oʻqiydi va uni brokerga yuboradi → holat va hodisa oʻrtasida hech qanday tafovut yoʻq.
Inbox: kelayotgan buyruqlar uchun’message _ id’va natijani bajarilgunga qadar saqlaymiz; qayta ishlash yozuvni koʻradi va nojoʻya taʼsirlarni takrorlamaydi.
4. 4 Zanjirga konsistent ishlov berish (read → process → write)
Kafka: tranzaksiya «ofsetni o’qib chiqdi → natijalarni yozib oldi → kommit» bitta atom blokiga.
Tranzaksiyasiz: «avval natijani/Inbox, keyin ack yozing»; kreshda dublikat Inbox ko’radi va no-op tugaydi.
4. 5 SAGA/kompensatsiya
Agar idempotentlik mumkin bo’lmasa (tashqi provayder pulni hisobdan chiqarsa), kompensatsiya operatsiyalari (refund/void) va idempotent tashqi APIlardan foydalanamiz (xuddi shu’Idempotency-Key’bilan takroriy’POST’xuddi shunday natijani beradi).
5) Qachon yetarli at-least-once
Kacheylarni/materiallashtirilgan ko’rsatmalarni kalit bo’yicha kompaksiya bilan yangilash.
Hisoblagichlar/metriklar, bu yerda takroriy inkrementatsiya maqbuldir (yoki delta versiyasini saqlaymiz).
Ikkilamchi xat muhim bo’lmagan notifikatsiyalar (baribir kalitni qo’yish yaxshiroqdir).
Qoida: agar dubl biznes ma’nosini o’zgartirmasa yoki osongina topsak → at-least-once + qisman himoya.
6) Unumdorlik va qiymat
Exactly-once (hatto «samarali») qimmatroq: qo’shimcha yozuvlar (Inbox/Outbox), kalitlarni saqlash, tranzaktsiyalar, diagnostika qilish qiyinroq.
At-least-once arzon/oson, yaxshiroq throughput/p99.
Baholang: dubl narxi × dubl ehtimoli vs himoya qiymati.
7) Konfiguratsiyalar va kod namunalari
7. 1 Kafka prodyuser (idempotentlik + tranzaksiyalar)
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 Inbox bilan konsumer (psevdokod)
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 (tashqi API)
POST /payments
Idempotency-Key: 7f1c-42-...
Body: { "payment_id": "p-123", "amount": 10.00 }
Bir xil kalit bilan qayta POST → bir xil natija/maqom.
8) Kuzatish va metrika
’duplicate _ attempts _ total’ - dublni necha marta ushlagan (Inbox/Redis boʻyicha).
’idempotency _ hit _ rate’ - idempotentlik bilan «qutqarilgan» takrorlar ulushi.
’txn _ abort _ rate’ (Kafka/DB) - qaytarishlar ulushi.
’outbox _ backlog’ - nashr ortda qolishi.
’exactly _ once _ path _ latency {p95, p99}’ vs’at _ least _ once _ path _ latency’- qo’shimcha xarajatlar.
Log auditi:’message _ id’,’idempotency _ key’,’saga _ id’,’attempt’.
9) Test-pleybuklar (Game Days)
Qayta jo’natish: Sun’iy taymautlarda prodyuser retrasi.
«Sink va ack»: Inbox/Upsert dublni oldini olishiga ishonch hosil qiling.
Qayta yetkazib berish: brokerda redelivery ko’paytirish; dedupni tekshirish.
Tashqi API idempotentligi: bir xil kalitli takroriy POST - bir xil javob.
Etakchi oʻzgarishi/tarmoq uzilishi: Kafka tranzaksiyalarini/konsumerlarning xatti-harakatlarini tekshirish.
10) Anti-patternlar
Transportga tayanish: «Bizda Kafka exactly-once bilan, demak kalitsiz bo’lishi mumkin» - yo’q.
No-op ack yozishdan oldin: ochildi, lekin sink yiqildi → yo’qotish.
Jitterli DLQ/retraylarning yo’qligi: cheksiz takrorlash va bo’ron.
Tabiiy kalitlar o’rniga tasodifiy UUID: hech narsa demontaj qilinmaydi.
Inbox/Outbox prod jadvallari bilan indekssiz aralashtirish: issiq blokirovka va p99-quyruqlar.
Tashqi provayderlarda idempotent APIsiz biznes-operatsiyalar.
11) Tanlov chek-varaqasi
1. Dubl narxi (pul/yuridik/UX) vs himoya narxi (yashirin/murakkablik/qiymat).
2. Hodisa/operatsiyaning tabiiy kaliti bormi? Agar yo’q bo’lsa, barqarorni o’ylab toping.
3. Sink Upsert/versiyalashni qoʻllab-quvvatlaydimi? Aks holda - Inbox + kompensatsiyalar.
4. Global tranzaksiyalar kerakmi? Agar yo’q bo’lsa, SAGA’da segmentlang.
5. Takrorlash/uzoq muddatli retenshn talab qilinadimi? Kafka + Outbox. Tezkor RPC/past kechikish kerakmi? NATS + Idempotency-Key.
6. Ko’p tenantlik va kvotalar: kalitlar/bo’shliqlarni izolyatsiya qilish.
7. Kuzatish darajasi: idempotency va backlog metriklari kiritilgan.
12) FAQ
Q: «Matematik» exactly-once end-to-end ga erishish mumkinmi?
A: Faqat butun yo’lda bitta konsistent saqlash va tranzaksiyalar bilan tor stsenariylarda. Umumiy holatda - yo’q; idempotentlik orqali exactly-once’dan samarali foydalaning.
Q: Nima tezroq?
A: At-least-once. Exactly-once tranzaksiyalarni qoʻshadi/kalitlarni saqlash → yuqori p99 va qiymati.
Q: Idempotentlik kalitlarini qayerda saqlash kerak?
A: TTL bilan tezkor stor (Redis) yoki Inbox jadvali (PK = message _ id). To’lovlar uchun - ko’proq (kunlar/haftalar).
Q: TTL dedup kalitlarini qanday tanlash mumkin?
A: Minimal = qayta yetkazib berishning maksimal vaqti + operatsion zaxirasi (odatda 24-72 soat). Moliya uchun - ko’proq.
Q: Agar Kafka’da compaction bo’lsa, menga kalit kerakmi?
A: Ha. Compaction saqlashni kamaytiradi, lekin sizning sinkingizni idempotent qilmaydi.
13) Yakunlar
At-least-once - transportning asosiy, ishonchli semantikasi.
Exactly-once biznes effekti sifatida Idempotency-Key, Inbox/Outbox, Upsert/versiya, SAGA/kompensatsiya darajasida erishiladi.
Tanlash - bu ikkilanish xavfi qiymatining murosasidir. Tabiiy kalitlarni loyihalashtiring, sinklarni idempotent qiling, kuzatish qobiliyatini qo’shing va muntazam ravishda o’yin kunlarini o’tkazing - shunda retray va nosozliklar bo’lganda ham payplaynlaringiz oldindan aytib bo’ladigan va xavfsiz bo’ladi.