İdempotentlik və açarlar
İdempotentlik nədir
İdempotentlik - eyni identifikatorla təkrarlanmanın yekun effekti dəyişmədiyi əməliyyat xüsusiyyətidir. Paylanmış sistemlərdə, retraya, mesajların təkrarlanmasına və taymautlara baxmayaraq, nəticəni «tam bir emala» bərabər etmək üçün əsas yoldur.
Əsas fikir: hər bir potensial təkrarlanan əməliyyat, sistemin «bunu artıq» tanıdığı və nəticəni bir dəfədən çox olmayan tətbiq etdiyi bir açarla qeyd edilməlidir.
Harada vacibdir
Ödənişlər və balanslar: 'operation _ id' üzrə hesabdan çıxarmalar/hesablaşmalar.
Rezervasyonlar/kvotalar/limitlər: eyni slot/resurs.
Vebhuki/bildirişlər: təkrar çatdırılma təsiri təkrarlamamalıdır.
İdxal/Miqrasiya: Faylların/paketlərin təkrar keçməsi.
Axın prosessinqi: broker/CDC-dən dubllar.
Açarların növləri və onların əhatə dairəsi
1. Operation key - biznes əməliyyatının konkret cəhdinin identifikatoru
Nümunələr: 'idempotency _ key' (HTTP), 'operation _ id' (RPC).
Sahə: xidmət/aqreqat; duplikasiya cədvəlində saxlanılır.
2. Event key - unikal hadisə/mesaj identifikatoru
Nümunələr: 'event _ id' (UUID), '(producer_id, sequence)'.
Sahə: istehlakçı/istehlakçı qrupu; proyeksiyaları qoruyur.
3. Business key - mövzu sahəsinin təbii açarı
Nümunələr: 'payment _ id', 'invoice _ number', '(user_id, day)'.
Sahə: aqreqat; unikallıq/versiya yoxlamalarında tətbiq olunur.
TTL və saxlama siyasəti
TTL açarları ≥ mümkün pəncərə təkrarları: giriş retensiyası + şəbəkə/proses gecikmələri.
Kritik domenlər üçün (ödənişlər) TTL - gün/həftə; telemetriya üçün - saat.
Dedup cədvəllərini cobamlarla təmizləyin; audit üçün - arxiv.
Anahtar anbarları (duplikasiya)
Əməliyyat DB (tövsiyə olunur): etibarlı upsert/unique indeksləri, effektli birgə əməliyyat.
KV/Redis: qısa TTL üçün tez, rahat, lakin ALTP ilə birgə əməliyyat olmadan - diqqətlə.
State store axın prosessor: yerli + broker chainjlog; Flink/KStreams yaxşı.
- idempotency_keys
`consumer_id` (или `service`), `op_id` (PK на пару), `applied_at`, `ttl_expires_at`, `result_hash`/`response_status` (опц.) .
Indekslər: '(consumer_id, op_id)' - unikaldır.
Əsas satış üsulları
1) Əməliyyat «effekt + tərəqqi»
Nəticənin yazılması və oxu/mövqe tərəqqisinin qeydə alınması - bir əməliyyatda.
pseudo begin tx if not exists(select 1 from idempotency_keys where consumer=:c and op_id=:id) then
-- apply effect atomically (upsert/merge/increment)
apply_effect(...)
insert into idempotency_keys(consumer, op_id, applied_at)
values(:c,:id, now)
end if
-- record reading progress (offset/position)
upsert offsets set pos=:pos where consumer=:c commit
2) Optimistic Concurrency (aqreqat versiyası)
Yarış zamanı ikiqat effektdən qoruyur:sql update account set balance = balance +:delta,
version = version + 1 where id=:account_id and version=:expected_version;
-- if 0 rows are updated → retry/conflict
3) İdempotent sinks (upsert/merge)
«Bir dəfə hesabla» əməliyyatı:sql insert into bonuses(user_id, op_id, amount)
values(:u,:op,:amt)
on conflict (user_id, op_id) do nothing;
Protokollarda idempotentlik
HTTP/REST
Başlıq 'Idempotency-Key: <uid' hash> '.
Server açar yazısını saxlayır və eyni cavabı qaytarır (və ya invariantlar toqquşması zamanı '409 '/' 422' kodu).
«Təhlükəli» POST üçün - «Idempotency-Key» + sabit vaxt/retraj siyasəti tələb olunur.
gRPC/RPC
Metadata 'idempotency _ key', 'request _ id' + deadline.
Server tətbiqi - REST-də olduğu kimi: əməliyyatda dedup cədvəli.
Brokerlər/axın (Kafka/NATS/Pulsar)
Prodüser: sabit 'event _ id '/idempotent prodüser (harada dəstəklənir).
Konsumer: dedup '(consumer_id, event_id)' və/və ya aqreqatın biznes versiyasına görə.
Qeyri-idempotent/zədələnmiş mesajlar üçün ayrı DLQ.
Vebhuk və xarici tərəfdaşlar
Müqavilədə 'Idempotency-Key '/' event _ id' tələb edin; təkrar çatdırılma təhlükəsiz olmalıdır.
'notification _ id' və göndərmə statuslarını saxlayın; retrada - təkrarlamayın.
Açar dizaynı
Determinasiya: retralar eyni açarı göndərməlidir (müştəri/orkestrdə əvvəlcədən yaradın).
Görünmə sahəsi: 'op _ id' kimi 'service: aggregate: id: purpose'.
Toqquşmalar: biznes parametrlərindən UUIDv7/ULID və ya hash istifadə edin (lazım olduqda duz ilə).
Hiyerarxiya: cəbhədə ümumi 'operation _ id' → bütün alt əməliyyatlarda yayımlanır (idempotent zənciri).
UX və məhsul aspektləri
Açar sorğusu eyni nəticəni (bədən/status daxil olmaqla) və ya açıq şəkildə «artıq yerinə yetirilmişdir».
«Uğur üçün» təkrar cəhd əvəzinə istifadəçiyə «əməliyyat işlənir/tamamlanır» statuslarını göstərin.
Uzun əməliyyatlar üçün - açar pollinqi ('GET/operations/{ op _ id}').
Müşahidə
'op _ id', 'event _ id', 'trace _ id', nəticə: 'APPLIED '/' ALREADY _ APPLIED'.
Metriklər: təkrarların payı, dedup cədvəllərinin ölçüsü, əməliyyatların vaxtı, versiya ziddiyyətləri, DLQ dərəcəsi.
Trace: açar komanda → hadisə → proyeksiya → xarici çağırış keçir lazımdır.
Təhlükəsizlik və uyğunluq
PII-ni açarda saxlamayın; açar - identifikator, heç bir payload.
Uzun TTL-də dədə qeydlərində həssas sahələri şifrələyin.
Saxlama siyasəti: TTL və arxivlər; unudulmaq hüququ - cavabların/meta məlumatların kriptovalyutası vasitəsilə (əgər onlar PII ehtiva edirsə).
Test
1. Təkrarlanan: bir mesaj/sorğu 2-5 dəfə - effekt tam olaraq bir.
2. Addımlar arasında düşmə: əvvəl/sonra efekt qeyd, əvvəl/sonra ofset fiksasiya.
3. Restart/istehlakçı balansı: ikiqat tətbiq yoxdur.
4. Rəqabət: bir 'op _ id' ilə paralel sorğular → bir effekt, ikinci - 'ALREADY _ APPLIED/409'.
5. Uzun ömürlü açarlar: TTL müddəti və bərpa edildikdən sonra təkrarları yoxlayın.
Antipatternlər
Hər retraya təsadüfi yeni açar: sistem təkrarları tanımır.
İki ayrı kommit: əvvəlcə effekt, sonra ofset - aralarında düşmə effekti təkrarlayır.
Yalnız brokerə güvən: çinka/aqreqatda babanın olmaması.
Aqreqat versiyasının olmaması: təkrar hadisə ikinci dəfə vəziyyəti dəyişir.
Fat keys: açar iş sahələri/PII → sızma və mürəkkəb indekslər daxildir.
Təkrar cavabların olmaması: müştəri təhlükəsiz şəkildə geri çəkilə bilməz.
Nümunələr
Ödəniş POST
Müştəri: 'POST/payments' + 'Idempotency-Key: k-789'.
Server: Əməliyyat - 'payment' və 'idempotency _ keys' yazısını yaradır.
Təkrar: eyni '201 '/bədən qaytarır; invariant qarşıdurmasında - '409'.
Bonus hesablanması (sink)
sql insert into credits(user_id, op_id, amount, created_at)
values(:u,:op,:amt, now)
on conflict (user_id, op_id) do nothing;
Hadisələrin proyeksiyası
Konsumer aqreqatın 'seen (event_id)' və 'version' saxlayır; təkrar - ignor/idempotent upsert.
Oxu tərəqqisi proyeksiyanın yenilənməsi ilə eyni əməliyyatda qeydə alınır.
Production çek siyahısı
- Bütün təhlükəli əməliyyatlar üçün idempotent açarı və onun görünmə sahəsi müəyyən edilmişdir.
- TTL və unikal indeksləri olan dedup cədvəlləri var.
- Okuma effekti və tərəqqi atomik olaraq birləşir.
- Write modelinə optimist rəqabət (versiya/sequence) daxildir.
- API müqavilələri 'idempotency-Key '/' operation _ id' və təkrarlama davranışını qeyd edir.
- Metrik və loglarda 'op _ id '/' event _ id '/' trace _ id' var.
- Təkrarlanan testlər, düşmə və yarış - CI.
- TTL/arxiv siyasəti və PII təhlükəsizlik riayət olunur.
FAQ
"Idempotency-Key" "Request-Id 'dən nə ilə fərqlənir?
'Request-Id' - izləmə; retralarda dəyişə bilər. 'Idempotency-Key' - əməliyyatın semantik identifikatoru, təkrarlandıqda eyni olmalıdır.
DB olmadan idempotentlik etmək mümkündürmü?
Qısa pəncərə üçün - bəli (Redis/prosesdaxili cache), lakin birgə əməliyyat olmadan dubl riski artır. Kritik domenlərdə - bir DB əməliyyatında daha yaxşıdır.
Xarici tərəfdaşlarla nə etmək lazımdır?
Açarlar və təkrar cavablar barədə razılığa gəlin. Tərəfdaş dəstəkləmirsə, çağırışı idempotent təbəqənizə çevirin və «artıq tətbiq olunub» saxlayın.
TTL necə seçilir?
Maksimum gecikmələri toplayın: log retensiyası + worst-case şəbəkəsi/rebalance + bufer. Ehtiyat əlavə edin (× 2).
Yekun
İdempotentlik açarların, əməliyyatların və versiyaların intizamıdır. Davamlı əməliyyat identifikatorları + okuma effekti və tərəqqisinin atom fiksasiyası + idempotent sinks/proyeksiyaları nəqliyyat səviyyəsinin sehri olmadan «tam bir effekt» verir. Açarları determinik, TTL - real və testlər - zərərli edin. Sonra retrajlar və dublikatlar hadisə deyil, rutin olacaq.