GH GambleHub

Exactly-once vs At-least-once

1) Nə üçün semantika müzakirə

Çatdırılma semantikası alıcının nasazlıqlar və retrajlar zamanı mesajı nə qədər tez-tez görəcəyini müəyyən edir:
  • At-most-once - təkrarsız, lakin itki mümkündür (nadir hallarda məqbul).
  • At-least-once - itirmirik, lakin dublikatlar mümkündür (əksər brokerlərin/növbələrin defoltu).
  • Exactly-once - Hər bir mesaj müşahidə olunan təsir baxımından düz bir dəfə emal edilir.

Əsas həqiqət: paylanmış dünyada qlobal əməliyyatlar və sinxron uyğunluq olmadan «təmiz» end-to-end exactly-once əlçatmazdır. Biz effektiv şəkildə exactly-once qururuq: nəqliyyatda təkrarlara icazə veririk, lakin emosional emal edirik ki, müşahidə olunan təsir 'bir dəfə kimi "olsun.


2) Uğursuzluq modeli və dublikatlar harada yaranır

Təkrar görə görünür:
  • ack/commit itkiləri (prodüser/broker/konsumer təsdiqini «eşitmədi»).
  • Liderlərin yenidən seçilməsi/replikaları, şəbəkə fasilələrindən sonra bərpa.
  • Hər hansı bir sahədə vaxt/retraut (müştəri → broker → konsumer → sink).

Nəticə: nəqliyyatın «unikallığına» etibar etmək olmaz. Effektləri idarə edirik: DB-yə yazmaq, pul çıxarmaq, məktub göndərmək və s.


3) Təchizatçılarda Exactly-once və əslində nə

3. 1 Kafka

Kərpiclər verir:
  • Idempotent Producer (`enable. idempotence = true ') - retralarda prodüserin tərəfində dublların qarşısını alır.
  • Əməliyyatlar - atomik olaraq bir neçə partiyaya və kommitat istehlak ofsetlərinə («keçidsiz» nümunə read-process-write) göndərilir.
  • Compaction - son açar dəyərini saxlayır.

Lakin «zəncirin sonu» (sink: BD/ödəniş/poçt) hələ də idempotentlik tələb edir. Əks halda, prosessor ikiqat təsir səbəb olacaq.

3. 2 NATS / Rabbit / SQS

Default - ack/redelivery ilə at-least-once. Exactly-once proqram səviyyəsində əldə edilir: açarlar, dedup-store, upsert.

Nəticə: Exactly-once nəqliyyat ≠ exactly-once effekt. Sonuncu prosessorda edilir.


4) at-least-once üzərində effektiv exactly-once qurmaq üçün necə

4. 1 Idempotent açarı (idempotency key)

Hər bir komanda/hadisə təbii açar daşıyır: 'payment _ id', 'order _ id #step', 'saga _ id #n'. Prosessor:
  • «Artıq gördünmü?» - TTL/retenshn ilə dedup stor (Redis/BD).
  • Gördüm - əvvəllər hesablanmış nəticəni təkrarlayır və ya no-op edir.
Redis eskizi:
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 bazasında (idempotent sink)

Qeydlər UPSERT/ON CONFLICT vasitəsilə versiyanın/məbləğin yoxlanılması ilə aparı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 Əməliyyat Outbox/Inbox

Outbox: Biznes əməliyyatı və «nəşr hadisələri» qeydləri bir DB əməliyyatında baş verir. Fon publisher outbox oxuyur və broker göndərir → vəziyyət və hadisə arasında heç bir uyğunsuzluq yoxdur.
Inbox: Daxil olan komandalar üçün 'message _ id' və nəticəni yerinə yetirilməzdən əvvəl saxlayın; təkrar emal qeyd görür və yan təsirləri təkrarlamır.

4. 4 Konsistent zəncir emalı (read → process → write)

Kafka: əməliyyat bir atom blokunda «ofset → qeyd → kommit» oxudu.
Əməliyyatlar olmadan: «əvvəlcə nəticə/Inbox, sonra ack yazın»; crash ikisini Inbox görəcək və no-op başa çatacaq.

4. 5 SAGA/kompensasiya

İdempotentlik mümkün olmadıqda (xarici provayder pulu silib), kompensasiya əməliyyatlarından (refund/void) və idempotent xarici API-lərdən (eyni 'Idempotency-Key' ilə təkrar 'POST' eyni nəticəni verir) istifadə edirik.


5) Kifayət zaman at-least-once

Açar kompaksiyası ilə cache/materiallaşdırılmış performans yeniləmələri.
Sayğaclar/metriklər, burada təkrar inkrementasiya məqbuldur (və ya delta versiyasını saxlayın).
İkinci məktubun kritik olmadığı qeydlər (yenə də açar qoymaq daha yaxşıdır).

Qayda: ikiqat iş mənasını dəyişdirmir və ya asanlıqla → at-least-once + qismən qorunma aşkar.


6) Performans və dəyəri

Exactly-once (hətta «effektiv») daha bahalıdır: əlavə qeyd (Inbox/Outbox), açarların saxlanması, əməliyyatlar, diaqnostika daha mürəkkəbdir.
At-least-once daha ucuz/daha asan, throughput/p99 ilə daha yaxşı.
Qiymətləndirin: ikiqat qiymət × ikiqat ehtimalı vs müdafiə dəyəri.


7) Konfiqurasiya və kod nümunələri

7. 1 Kafka prodüseri (idempotentlik + əməliyyatlar)

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 ilə 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 (xarici API)


POST /payments
Idempotency-Key: 7f1c-42-...
Body: { "payment_id": "p-123", "amount": 10.00 }

Eyni açar ilə POST təkrar → eyni nəticə/status.


8) Müşahidə və metrika

'duplicate _ attempts _ total' - neçə dəfə dubl (Inbox/Redis ilə).
'idempotency _ hit _ rate' - idempotentliyi ilə «xilas edilmiş» təkrarların payı.
'txn _ abort _ rate' (Kafka/BD) - geri çəkilmələrin payı.
'outbox _ backlog' - nəşr gecikməsi.
'exactly _ once _ path _ latency {p95, p99}' vs 'at _ least _ once _ path _ latency' - əlavə xərclər.
Log auditi: 'message _ id', 'idempotency _ key', 'saga _ id', 'attempt'.


9) Test Playbook (Game Days)

Göndərmənin təkrarı: prodüserin süni vaxtlarda retrayları.
«Sink & ack» arasında Crash: Inbox/Upsert ikiqat qarşısını almaq üçün əmin olun.
Yenidən çatdırılma: broker redelivery artırmaq; dedupu yoxlamaq.
Xarici API idempotentliyi: eyni açarla təkrar POST eyni cavabdır.
Lider dəyişikliyi/şəbəkə qırılması: Kafka əməliyyatlarını/konsumerlərin davranışlarını yoxlayın.


10) Anti-nümunələr

Nəqliyyata güvənmək: «Bizdə Kafka exactly-once var, yəni açarsız mümkündür» - yox.
No-op ack qeyd əvvəl: ackled, lakin sink düşdü → itki.
DLQ/Jitter retrains yoxdur: sonsuz təkrarlamalar və fırtına.
Təbii açarlar əvəzinə təsadüfi UUID: deduplication heç bir şey.
Inbox/Outbox-u indeks olmadan prod cədvəlləri ilə qarışdırın: isti kilidləmə və p99-quyruqlar.
Xarici provayderlərdə idempotent API olmadan biznes əməliyyatları.


11) Check-list seçimi

1. ikiqat qiymət (pul/hüquq/UX) vs müdafiə qiymət (gizli/mürəkkəblik/dəyəri).
2. Hadisənin/əməliyyatın təbii açarı varmı? Əgər yoxdursa, sabit fikirləşin.
3. Sink Upsert/version dəstəkləyir? Əks halda - Inbox + kompensasiya.
4. Qlobal əməliyyatlara ehtiyacınız varmı? Yoxsa, SAGA-da seqmentləşdirin.
5. Replica/uzun gecikmə tələb olunur? Kafka + Outbox. Sürətli RPC/aşağı gecikmə lazımdır? NATS + Idempotency-Key.
6. Çox tenantlıq və kvotalar: açarların/məkanların izolyasiyası.
7. Müşahidə: idempotency və backlog metriklər daxildir.


12) FAQ

Q: «riyazi» exactly-once end-to-end əldə etmək mümkündürmü?
A: Yalnız bütün yolda bir konsistent saxlama və əməliyyatlar ilə dar ssenarilərdə. Ümumiyyətlə - yox; səmərəli idempotentlik vasitəsilə exactly-once istifadə edin.

Q: Hansı daha sürətli?
A: At-least-once. Exactly-once əməliyyat/anahtar saxlama → p99 yuxarıda və dəyəri əlavə edir.

Q: İdempotent açarları harada saxlanılır?
A: TTL ilə sürətli stor (Redis) və ya Inbox cədvəli (PK = message _ id). Ödənişlər üçün - daha uzun (gün/həftə).

Q: TTL dedup açarları necə seçilir?
A: Minimum = maksimum təkrar çatdırılma vaxtı + əməliyyat ehtiyatı (adətən 24-72 saat). Maliyyə üçün - daha çox.

Q: Mən Kafka açar compaction varsa açar lazımdır?
A: Bəli. Compaction saxlama azaldacaq, lakin sink idempotent etməyəcək.


13) Nəticələr

At-least-once - əsas, etibarlı nəqliyyat semantikası.
İş effekti kimi Exactly-once prosessor səviyyəsində əldə edilir: Idempotency-Key, Inbox/Outbox, Upsert/versiyası, SAGA/kompensasiya.
Seçim - güzəşt dəyəri, iki dəfə riskdir. Təbii açarları layihələndirin, çəngəlləri idempotent edin, müşahidə əlavə edin və mütəmadi olaraq oyun günləri keçirin - sonra retraj və uğursuzluqlar fırtınasında belə paylayıcılarınız proqnozlaşdırıla bilən və təhlükəsiz olacaq.

Contact

Bizimlə əlaqə

Hər hansı sualınız və ya dəstək ehtiyacınız varsa — bizimlə əlaqə saxlayın.Həmişə köməyə hazırıq!

İnteqrasiyaya başla

Email — məcburidir. Telegram və ya WhatsApp — istəyə bağlıdır.

Adınız istəyə bağlı
Email istəyə bağlı
Mövzu istəyə bağlı
Mesaj istəyə bağlı
Telegram istəyə bağlı
@
Əgər Telegram daxil etsəniz — Email ilə yanaşı orada da cavab verəcəyik.
WhatsApp istəyə bağlı
Format: ölkə kodu + nömrə (məsələn, +994XXXXXXXXX).

Düyməyə basmaqla məlumatların işlənməsinə razılıq vermiş olursunuz.