Mesajların qaydasına zəmanət
1) «sifariş» nədir və niyə lazımdır
Mesaj qaydası bir mahiyyət hadisələri (sifariş, istifadəçi, cüzdan) və ya bütün axın üçün «nə əvvəl işlənməlidir» münasibətidir. Bu invariantlar üçün vacibdir: «B-dən əvvəl A statusu», «silinmədən əvvəl balans», «n + 1-dən əvvəl n versiyası».
Paylanmış sistemlərdə qlobal ümumi yol qaydası və nadir hallarda lazımdır; adətən «açar» yerli sifariş kifayətdir.
2) Sifariş zəmanətlərinin növləri
1. Per-partition (log bölməsində yerli nizam) - Kafka: partiya daxilində nizam saxlanılır, partiyalar arasında - yoxdur.
2. Per-key (ordering key/message group) - bütün mesajlar bir «axın» emalına (Kafka key, SQS FIFO MessageGroupId, Pub/Sub ordering key) yönləndirilir.
3. Global total order - bütün sistem vahid sifariş (paylanmış jurnal/sekvenser) görür. Bahalı, mövcudluğu pisləşdirir və throughput.
4. Causal order (səbəb-nəticə) - «B A təsiri müşahidə əgər A sonra hadisə». Qlobal sekvenser olmadan meta-məlumatlarla (versiyalar, Lamport-time/vektor saatlar) əldə edilə bilər.
5. Best-effort order - broker nizam-intizamı qorumağa çalışır, lakin uğursuzluqlar ola bilər (çox vaxt NATS Core, RabbitMQ bir neçə konsumerdə).
3) Harada nizam pozulur
Paralel bir sıra konsumerlər (RabbitMQ: bir sıra → interleaving üçün bir neçə consumers).
Retray/təkrar çatdırılma (at-least-once), 'ack' taymautları, yenidən növbəyə qoyulması.
Rebalans/Feylover (Kafka: partiyanın/liderin hərəkəti).
DLQ/təkrar emal - «zəhərli» mesaj DLQ gedir, sonrakı → məntiqi boşluq.
Multi-region və replikasiya - müxtəlif gecikmələr → rassinxronizasiya.
4) Dizayn «açar sifariş»
Açar "nizamlama vahidi 'ni formalaşdırır. Tövsiyələr:- Təbii açarları istifadə edin: 'order _ id', 'wallet _ id', 'aggregate _ id'.
- «Qaynar açarları» izləyin - bir açar axını «bloklaya» bilər (head-of-line blocking). Lazım gələrsə, açarı parçalayın: 'order _ id #shard (0.. k-1)' determinik yenidən qurulması ilə.
- Kafka 'da - bir açar → bir hissə, sıra açar daxilində qalacaq.
java producer.send(new ProducerRecord<>("orders", orderId, eventBytes));
(Açar = 'orderId' yerli qaydaya zəmanət verir.)
5) «Bant genişliyinə qarşı sifariş»
Güclü zəmanətlər tez-tez throughput və mövcudluğu ilə ziddiyyət təşkil edir:- Növbə üçün bir konsumer qaydanı saxlayır, lakin paralelliyi azaldır.
- At-least-once + paralellik performansı artırır, lakin idempotentlik və/və ya nizam bərpa tələb edir.
- Global order sekvenserə hop əlavə edir → ↑ gizlilik və imtina riski.
Kompromis: per-key sifariş, paralellik = partiyalar/qrupların sayı, + idempotent sink.
6) Xüsusi broker nizam nəzarət
Kafka
Partiya daxilində nizam.
'max. in. flight. requests. per. connection ≤ 5` с `enable. idempotence = true 'ki, prodüserin retrayları qaydanı dəyişməsin.
Konsumer qrupu: bir partiya → bir anda bir vorker. Yenidən çatdırılma mümkündür → sequence/version biznes təbəqəsində saxlayın.
Tranzaksiyalar (read-process-write) «oxu/qeyd/skommitil ofset» ardıcıllığını saxlayır, lakin qlobal sifariş yaratmır.
properties enable.idempotence=true acks=all retries=2147483647 max.in.flight.requests.per.connection=5
RabbitMQ (AMQP)
Sifariş bir müştəri üçün bir növbədə təmin edilir. Bir neçə mesaj məsləhətçisi ilə «qarışıq» gələ bilər.
Sifariş üçün: bitdikdən sonra bir konsumer və ya prefetch = 1 + ack. Paralellik üçün - açar sıralarını bölün (sharding exchanges/consistent-hash exchange).
NATS / JetStream
NATS Core - ən yaxşı effort, aşağı gecikmə, sifariş pozula bilər.
JetStream: axın/ardıcıllıq daxilində nizam; Nadir hallarda konsumerdə yerdəyişmələr mümkündür → sequence və bərpa buferi istifadə edin.
SQS FIFO
Exactly-once processing (səmərəli, babasının hesabına) və MessageGroupId daxilində nizam. Paralellik - qrupların sayı, qrup daxilində head-of-line.
Google Pub/Sub
Ordering key açar daxilində sifariş verir; səhv olduqda, nəşr bərpa əvvəl bloklanır - backpressure izləyin.
7) Qaydanın qorunması və bərpası nümunələri
7. 1 Sequence/versiyası
Hər bir hadisə 'seq '/' version' daşıyır. Konsumer:- hadisəni yalnız 'seq = last_seq + 1' olduqda qəbul edir;
- əks halda - itkin gələnə qədər gözləmə tamponuna qoyur ('last _ seq + 1').
pseudo if seq == last+1: apply(); last++
else if seq > last+1: buffer[seq] = ev else: skip // дубль/повтор
7. 2 Buferlər və pəncərələr (stream processing)
Time-window + watermark: pəncərə daxilində out-of-order qəbul, watermark vasitəsilə pəncərəni «bağlayın» və nizamlayın.
Allowed lateness: gecikənlər üçün kanal (recompute/ignore).
7. 3 Sticky-routing açar
'hash (key)% shards' hash marşrutu bütün açar hadisələrini bir worker-ə göndərir.
Kubernetes-də - sessiyanı (sticky) L4 balanslayıcısında deyil, növbə/şerda səviyyəsində saxlayın.
7. 4 Actor modeli/« açar başına bir axın »
Kritik aqreqatlar üçün (pul kisəsi): aktyor ardıcıl olaraq emal edir, qalan paralellik - aktorların sayı ilə.
7. 5 İdempotentlik + reordering
Düzənin bərpası ilə belə təkrarlamalar mümkündür. UPSERT + versiyasını Inbox ilə birləşdirin (bax: «Exactly-once vs At-least-once»).
8) «zəhərli» mesajlarla işləmək (poison pills)
Sifarişin qorunması vəzifəsi ilə üzləşir: «Bir mesaj emal edilmədikdə necə yaşamaq olar?»
Ciddi sifariş: açar axını bloklanması (SQS FIFO: bütün qrup). Həll yolu - by-key DLQ: yalnız problem açarını/qrupunu ayrıca növbəyə/əl analizinə köçürürük.
Çevik sifariş: keçid/kompensasiya icazə; loging və davam (maliyyə/kritik aqreqatlar üçün deyil).
Retraj siyasəti: məhdud 'max-deliver' + backoff + avidempotent effektləri.
9) Multi-region və qlobal sistemlər
Cluster-linking/replikasiya (Kafka) regionlararası qlobal nizama zəmanət vermir. Yerli per-key sifarişinə və idempotent sinklərinə üstünlük verin.
truly-global order üçün sekvenser (mərkəzi log) istifadə edin, lakin bu əlçatanlığa təsir edir (CAP: şəbəkə boşluqlarında mənfi A).
Alternativ: bəzi domenlər (sayğaclar, çoxluqlar) üçün causal order + CRDT - ciddi sifariş tələb etmir.
10) Sıra müşahidə
Метрики: `out_of_order_total`, `reordered_in_window_total`, `late_events_total`, `buffer_size_current`, `blocked_keys_total`, `fifo_group_backlog`.
11) Anti-nümunələr
Bir sıra + açar olmadan bir çox konsumer - sifariş dərhal pozulur.
idempotency olmadan eyni sırada pere-publich vasitəsilə retrai - dubli + out-of-order.
Qlobal sifariş «hər ehtimala qarşı» - real faydası olmadan gizli və dəyərli partlayış.
SQS FIFO bütün bir qrup - tam baş-of-line. MessageGroupId per açarını istifadə edin.
"Qaynar açarlar 'a məhəl qoymamaq - bir" cüzdan "hər şeyi yavaşlatır; açarı mümkün olan yerdə alt açarlara bölün.
Kritik və bulk axınlarının bir sıra/qrupda qarışdırılması qarşılıqlı təsir və nizam itkisidir.
12) Giriş çek siyahısı
- Zəmanət səviyyəsi müəyyən edilmişdir: per-key/per-partition/causal/global?
- Sifariş açarı və "isti açarlar 'a qarşı strategiya hazırlanmışdır.
- Router konfiqurasiya :/MessageGroupId/ordering key.
- Konsumerlər açarlar (sticky-routing, shard-workers) ilə təcrid olunur.
- Sinklərdə idempotentlik və/və ya Inbox/UPSERT daxildir.
- sequence/version və bufer reordering həyata keçirilmişdir (lazım olduqda).
- DLQ siyasəti by key və backoff ilə retrai.
- Sıra metrikası və risklər: out-of-order, blocked_keys, late_events.
- Game day: rebalance, düyün itkisi, «zəhərli» mesaj, şəbəkə gecikmələri.
- Sənədləşmə: invariant sifariş, pəncərə sərhədləri, SLA təsir.
13) Konfiqurasiya nümunələri
13. 1 Kafka Consumer (qaydanın pozulmasını minimuma endirmək)
properties max.poll.records=500 enable.auto.commit=false # коммит после успешной обработки батча isolation.level=read_committed
13. 2 RabbitMQ (paralellik bahasına sifariş)
Növbə üçün bir konsumer + 'basic. qos(prefetch=1)`
Paralellik üçün - bir neçə növbə və hash-exchange:bash rabbitmq-plugins enable rabbitmq_consistent_hash_exchange публикуем с хедером/ключом для консистентного хеша
13. 3 SQS FIFO
MessageGroupId = key. Paralellik = qrupların sayı.
MessageDeduplicationId (provayder pəncərəsində).
13. 4 NATS JetStream (ordered consumer, eskiz)
bash nats consumer add ORDERS ORD-KEY-42 --filter "orders.42.>" --deliver pull \
--ack explicit --max-deliver 6
14) FAQ
Q: Mən qlobal sifariş lazımdır?
A: Demək olar ki, heç vaxt. Demək olar ki, həmişə per-key kifayətdir. Qlobal nizam bahadır və əlçatanlığa zərbə vurur.
Q: ciddi qaydada «zəhərli» mesaj haqqında necə?
A: Yalnız onun açarını/qrupunu DLQ-yə köçürmək, qalanını davam etdirmək.
S: Sifariş və miqyas eyni vaxtda əldə edilə bilərmi?
A: Bəli, açar qaydası + bir çox açar/partiyalar + idempotent əməliyyatlar və lazımi yerlərdə tamponlar.
Q: Hansı daha vacibdir: sifariş və ya exactly-once?
A: Əksər domenlər üçün - açar qaydası + effektiv exactly-once effektləri (idempotentlik/UPSERT). Nəqliyyat at-least-once ola bilər.
15) Nəticələr
Sifariş biznes açarı ətrafında yerli zəmanətdir, bahalı qlobal intizam deyil. Açarları və hissələri layihələndirin, «qaynar» açarları məhdudlaşdırın, idempotluq və lazım olduqda sequence + bufer reordering istifadə edin. «Out-of-order» və «blocked keys» metriklərini izləyin, uğursuzluqları sınayın - və performans və əlçatanlıqda qurbanlar olmadan proqnozlaşdırıla bilən emal alacaqsınız.