Mesaj siparişi garantileri
1) "Düzen'nedir ve neden gereklidir?
Mesajların sırası, bir varlığın olayları (sipariş, kullanıcı, cüzdan) veya tüm akış için'daha önce işlenmesi gerekenler "ilişkisidir. Değişmezler için önemlidir: "B'den önce durum A", "yazmadan önce denge", "n + 1'den önce n sürümü".
Dağıtılmış sistemlerde, küresel toplam sipariş pahalıdır ve nadiren gereklidir; Yerel anahtar başına sipariş genellikle yeterlidir.
2) Sipariş garantisi türleri
1. Per-partition (log bölümündeki yerel düzen) - Kafka: parti içindeki düzen korunur, partiler arasında - hayır.
2. Per-key (sipariş anahtarı/mesaj grubu) - tek anahtarlı tüm iletiler tek bir işleme "iş parçacığı'na yönlendirilir (Kafka anahtarı, SQS FIFO MessageGroupId, Pub/Sub sipariş anahtarı).
3. Küresel toplam sipariş - tüm sistem tek bir sipariş görür (dağıtılmış dergi/sequencer). Pahalı, kullanılabilirliği ve verimi düşürür.
4. Nedensel düzen - "event B after A if B observes effect A" Global bir sıralayıcı olmadan meta veriler (versiyonlar, Lamport-times/vektör saatleri) aracılığıyla ulaşılabilir.
5. En iyi çaba siparişi - komisyoncu düzeni korumaya çalışır, ancak arıza durumunda permütasyonlar mümkündür (genellikle NATS Core, RabbitMQ'da birkaç tüketici ile).
3) Siparişin bozulduğu yer
Aynı kuyruğun paralel tüketicileri (RabbitMQ: kuyruk başına birkaç tüketici - interleaving).
Retrays/yeniden teslimatlar (en az bir kez), 'ack' zaman aşımları, yeniden sıraya alma.
Rebalance/feilover (Kafka: parti/lider hareketi).
DLQ/yeniden işleme - "zehirli" mesaj DLQ'ya gider, bir sonraki daha ileri gider - mantıksal bir mola.
Çok bölgeli ve çoğaltma - farklı gecikmeler - yanlış hizalama.
4) Anahtar sipariş tasarımı
Anahtar "sipariş birimi'ni oluşturur. "Öneriler:- Doğal anahtarları kullanın: 'order _ id', 'wallet _ id', 'aggregate _ id'.
- "Kısayol tuşları'nı izleyin - bir anahtar akışı" engelleyebilir "(satır başı engelleme). Gerekirse, anahtarı bölün: 'order _ id # shard (0.. K-1) 'lavabo üzerindeki düzenin deterministik yeniden inşası ile.
- Kafka'da - bir anahtar - bir parça, düzen anahtar içinde korunacaktır.
java producer.send(new ProducerRecord<>("orders", orderId, eventBytes));
(Key = 'orderId' yerel düzeni garanti eder.)
5) "Sipariş ve Bant Genişliği"
Güçlü garantiler genellikle verim ve kullanılabilirlik ile çakışır:- Kuyruk başına bir tüketici düzeni korur ancak eşzamanlılığı azaltır.
- En az bir kez + eşzamanlılık performansı artırır, ancak idempotency ve/veya yeniden sıralama gerektirir.
- Küresel düzen, sıralayıcıya hop ekler - ↑latentnost ve başarısızlık riski.
Uzlaşma: anahtar başına düzen, paralellik = parti/grup sayısı, + idempotent çürükler.
6) Belirli brokerlerde düzenin kontrolü
Kafka
Parti içinde düzen.
Observe 'max. İçeri. Uçuş. Talepler. Per. bağlantı ≤ 5 'с' etkinleştir. Idempotence = true 'böylece üreticinin retrays düzeni değiştirmez.
Tüketici grubu: Bir parti - bir seferde bir işçi. Tekrarlanan teslimatlar mümkündür - iş katmanında sıra/versiyon tutun.
Okuma-yazma işlemleri okuma/yazma/kırıntı dengeleme tutarlılığını korur, ancak küresel bir düzen oluşturmaz.
properties enable.idempotence=true acks=all retries=2147483647 max.in.flight.requests.per.connection=5
RabbitMQ (AMQP)
Sipariş, bir tüketim için bir kuyrukta garanti edilir. Birkaç mesaj tüketicisiyle "karışık" gelebilir.
Sipariş için: bittiğinde bir tüketen veya prefetch = 1 + ack. Eşzamanlılık için, kuyrukları anahtarlara göre ayırın (sharding exchange/compliant-hash exchange).
NATS/JetStream
NATS Core - en iyi çaba, düşük gecikme, sipariş bozulmuş olabilir.
JetStream: akış/sıra içinde sipariş; Yeniden teslimat sırasında, konsoldaki yeniden düzenlemeler mümkündür - kullanım sırası ve kurtarma arabelleği.
SQS FIFO
MessageGroupId içinde tam olarak bir kez işleme (veri tekilleştirme nedeniyle etkili bir şekilde) ve sipariş. Eşzamanlılık - bir satır başı grubundaki grupların sayısı.
Google Pub/Sub hakkında
Sipariş anahtarı, anahtar içindeki siparişi verir; Hata durumunda, yayınlama geri yüklenene kadar engellenir - geri basmaya dikkat edin.
7) Düzeni koruma ve geri yükleme kalıpları
7. 1 Sıra/sürüm oluşturma
Her olay bir 'seq'/' version' taşır. Tüketim:- Bir olayı yalnızca 'seq = last_seq + 1';
- Aksi takdirde - eksik ('last _ seq + 1') gelmeden önce bekleme arabelleği koyar.
pseudo if seq == last+1: apply(); last++
else if seq > last+1: buffer[seq] = ev else: skip // дубль/повтор
7. 2 Tamponlar ve pencereler (akış işleme)
Zaman penceresi + filigran: Pencerenin içinde sıra dışı kabul ediyoruz, filigrana göre pencereyi "kapatıyoruz've düzenliyoruz.
İzin verilen gecikme: geç gelenler için kanal (yeniden hesaplama/yoksayma).
7. 3 Anahtarla yapışkan yönlendirme
Hash (key) % shards hash yönlendirmesi tüm önemli olayları tek bir çalışana gönderir.
Kubernetes'te - L4 HTTP dengeleyicisinde değil, kuyruk/şeritler düzeyinde bir oturum (yapışkan) tutun.
7. 4 Aktör-model/" anahtar başına bir akış"
Kritik toplamlar (cüzdan) için: aktör sırayla işler, paralelliğin geri kalanı - aktörlerin sayısı.
7. 5 Idempotence + yeniden sıralama
Düzenin yeniden kurulmasıyla bile tekrarlar mümkündür. UPSERT'i anahtar + sürüm ve Gelen Kutusu ile birleştirin (bkz. Tam Olarak bir kez vs En az bir kez).
8) "Zehirli" mesajlarla çalışın (zehirli haplar)
Düzeni korumak şu görevle karşı karşıyadır: "Bir mesaj işlenmezse nasıl yaşanır?"
Sıkı düzen: anahtar akış engelleme (SQS FIFO: tüm grup). Çözüm, by-key DLQ'dur: yalnızca sorun anahtarını/grubunu ayrı bir kuyruğa/manuel ayrıştırmaya aktarırız.
Esnek düzen: atlama/telafiye izin veriyoruz; Günlüğe kaydediyoruz ve devam ediyoruz (finans/kritik toplamlar için değil).
Retray ilkesi: sınırlı 'max-deliver' + backoff + avidempotent etkileri.
9) Çok bölgeli ve küresel sistemler
Cluster-linking/replication (Kafka) bölgeler arası global düzeni garanti etmez. Yerel anahtar başına sıraya ve idempotent çürüklere öncelik verin.
Gerçekten global sipariş için, bir sıralayıcı (merkezi günlük) kullanın, ancak bu kullanılabilirliği etkiler (CAP: Ağ sonları için eksi A).
Alternatif: Nedensel düzen + bazı alanlar için CRDT (sayaçlar, kümeler) - katı bir düzen gerekmez.
10) Düzenin gözlemlenebilirliği
Метрики: 'out _ of _ order _ total', 'reordered _ in _ window _ total', 'late _ events _ total', 'buffer _ size _ current', 'blocked _ keys _ total', 'fifo _ group _ backlog'.
11) Anti-desenler
Bir kuyruk + anahtar üzerinde sharding olmadan birçok tüketici - sipariş hemen bozulur.
Retrai, idempotency olmadan aynı kuyrukta yeniden halka açık - çiftler + sıra dışı.
Küresel'her ihtimale karşı "düzeni, gerçek bir yararı olmayan bir gecikme ve değer patlamasıdır.
SQS FIFO Herkes için bir grup - tam hat başı. Anahtar başına MessageGroupId kullanın.
"Sıcak anahtarlar'ı görmezden gelmek - bir" cüzdan'her şeyi yavaşlatır; Mümkünse anahtarı alt anahtarlara bölün.
Kritik ve toplu akışları aynı kuyrukta/grupta karıştırmak - karşılıklı etki ve sipariş kaybı.
12) Uygulama kontrol listesi
- Per-key/per-partition/causal/global?
- Sıralama anahtarı ve anti-hot anahtar stratejisi tasarlanmıştır.
- Yönlendirici yapılandırılmış: bölümleme/MessageGroupId/sipariş anahtarı.
- Konsollar tuşlarla izole edilir (yapışkan yönlendirme, parça işçileri).
- Morluklar üzerinde Idempotency ve/veya Inbox/UPSERT dahildir.
- Uygulanan dizi/sürüm ve yeniden sıralama arabelleği (gerekirse).
- DLQ, anahtar politika ve geri alma geri dönüşlerine göre.
- Sıra dışı, blocked_keys, late_events sipariş ve uyarı metrikleri.
- Oyun günü: yeniden dengeleme, düğüm kaybı, zehirli mesaj, ağ gecikmeleri.
- Dokümantasyon: sipariş değişmezleri, pencere sınırları, SLA'lar üzerindeki etkisi.
13) Yapılandırma örnekleri
13. 1 Kafka Tüketici (sipariş ihlali minimizasyonu)
properties max.poll.records=500 enable.auto.commit=false # коммит после успешной обработки батча isolation.level=read_committed
13. 2 RabbitMQ (eşzamanlılık fiyatına göre sipariş)
Kuyruk başına bir tüketici + 'temel. qos (prefetch = 1) '
Eşzamanlılık için - birkaç kuyruk ve hash-exchange:bash rabbitmq-plugins enable rabbitmq_consistent_hash_exchange публикуем с хедером/ключом для консистентного хеша
13. 3 SQS FIFO
MessageGroupId = anahtarını ayarlayın. Eşzamanlılık = grup sayısı.
MessageDeduplicationId yinelenmelere karşı koruma için (sağlayıcı penceresinde).
13. 4 NATS JetStream (sipariş edilen tüketici, taslak)
bash nats consumer add ORDERS ORD-KEY-42 --filter "orders.42.>" --deliver pull \
--ack explicit --max-deliver 6
Anahtar> Uygulamadaki 'eşitlik've yeniden sıralama arabelleğini izleyin.
14) SSS
S: Küresel bir düzene ihtiyacım var mı?
A: Neredeyse hiç. Neredeyse her zaman anahtar başına yeterli. Küresel düzen pahalıdır ve satın alınabilirliği vurur.
S: Peki ya katı düzen altındaki "zehirli" mesaj?
C: Sadece anahtarını/grubunu DLQ'ya aktarın, gerisi - devam edin.
S: Aynı anda sipariş ve ölçek alabilir misiniz?
C: Evet, anahtar sırası + birçok anahtar/parça + idempotent işlemleri ve gerektiğinde tamponların yeniden sıralanması.
S: Hangisi daha önemli: düzen mi yoksa tam olarak bir kez mi?
C: Çoğu etki alanı için - anahtar sırası + etkili bir şekilde tam bir kez etkileri (idempotency/UPPERT). Ulaşım en az bir kez olabilir.
15) Toplam
Sipariş, işletme anahtarı etrafında yerel bir garantidir, pahalı bir küresel disiplin değildir. Anahtarları ve partileri tasarlayın, kısayol tuşlarını sınırlayın, idempotence kullanın ve gerektiğinde arabelleği sıralayın + yeniden sıralayın. Sıra dışı ve engellenen anahtar metriklerine, test çökmelerine dikkat edin ve performans veya kullanılabilirlikten ödün vermeden öngörülebilir işlemler elde edin.