GH GambleHub

來文程序的保障

1)什麼是「秩序」,為什麼需要它

消息順序是單個實體(訂單,用戶,錢包)或整個線程的事件「必須先處理」的關系。它對於不變量很重要:「B之前的狀態A」,「註銷前的平衡」,「n+1之前的版本n」。
在分布式系統中,很少需要全球總道路順序;通常,「按鍵」的本地順序就足夠了。


2)秩序保證的類型

1.Per-partition (log部分中的本地順序)-Kafka:黨內順序保持不變,黨內順序保持不變。
2.按鍵(ordering key/message group)-將所有單鍵消息路由到一個處理的「線程」(Kafka key, SQS FIFO MessageGroupId, Pub/Sub ordering key)。
3.全球總命令-整個系統看到一個順序(分布式日誌/音序器)。價格昂貴,降低了可用性和通量。
4.Causal order(因果關系)是「如果B觀察到A效應,則事件B之後」。無需全局測序器即可通過元數據(版本,Lamport時間/矢量時鐘)實現。
5.Best-effort order-經紀人試圖保持秩序,但是如果失敗,可能會進行重新排列(通常在NATS Core,RabbitMQ中使用多個對齊器)。


3)訂單中斷的地方

一隊列並行消費者(RabbitMQ:每個隊列多個消費者→ interleaving)。
Retrai/重新交付(at least-once),taymauts 「ack」,重新排隊。
Rebalans/feilover(Kafka:政黨/領導人的舉動)。
DLQ/重新處理-「有毒」消息離開DLQ,接下來是邏輯中斷→。
多區域和復制-不同的延遲→同步。


4)「按鍵順序」設計"

密鑰形成「排序單元」。建議:
  • 使用自然鍵:'order_id'、'wallet_id'、'aggregate_id'。
  • 留意「熱鍵」-單鍵可以「鎖定」流(頭對頭鎖定)。如果需要,分解鍵:'order_id#shard (0.. k-1)",在合成器上進行確定性順序重建。
  • 在Kafka中-一個鍵→一個部分,訂單將保持在鍵內。
示例(Kafka,Java):
java producer.send(new ProducerRecord<>("orders", orderId, eventBytes));

(鍵='orderId'保證了本地順序。)


5)「訂單與容量」

強大的保修通常與通配符和可訪問性發生沖突:
  • 每個隊列一個匹配器保留順序,但減少並發。
  • At-least-once+並發可以提高性能,但需要等速和/或階還原。
  • Global Order為音序器添加了嘻哈→ ↑latentnost和故障風險。

折衷方案:按鍵順序,並行=政黨/團體數,+等效辛基。


6)控制特定經紀人的秩序

Kafka

黨內的秩序。
遵守'max。in.flight.requests.per.connection ≤ 5` с `enable.idempotence=true',這樣制片人的復制品就不會改變順序。
Consumer Group:一方→一方。可以重復交付→將序列/版本保持在業務層中。
事務(read-process-write)保持一致性「讀取/寫入/錯配」,但不創建全局順序。

生產最低限度(生產者。properties):

properties enable.idempotence=true acks=all retries=2147483647 max.in.flight.requests.per.connection=5

RabbitMQ (AMQP)

單個concumer的順序保證為單隊列。多個消息匹配器可能會出現「前進」。
對於順序:完成後,單個consumer或prefetch=1+ack。對於並行-按鍵劃分隊列(sharding exchanges/consistent-hash exchange)。

NATS / JetStream

NATS Core-最好的effort,低潛伏期,訂單可能會中斷.

JetStream:在流/序列中排序;如果重新排列,則可以重新排列concumer,→使用序列和恢復緩沖區。

SQS FIFO

Exactly once processing(有效,通過重復數據消除)和MessageGroupId中的順序。並發是線頭組內的組數。

Google Pub/Sub

Ordering鍵在鍵內給出一個順序;如果出現錯誤,則在恢復之前會阻止發布-請註意後退。


7)保存和恢復秩序的模式

7.1個序列/轉化

每個事件都帶有「seq」/「版本」。Consumer:
  • 僅在「seq=last_seq+1」時接受事件;
  • 否則-在失蹤人員到達之前(「last_seq+1」)放置在等待緩沖區。
偽代碼:
pseudo if seq == last+1: apply(); last++
else if seq > last+1: buffer[seq] = ev else: skip // дубль/повтор

7.2緩沖區和窗口(流處理)

Time-window+watermark:在窗口內接受訂單外,在watermark上「關閉」窗口並排序。
Allowed lateness:遲到的頻道(recompute/ignore)。

7.3按鍵按鍵sticky-routing

哈希路由「hash (key)% shards」將所有密鑰事件發送到單個用戶。
在Kubernetes-支持隊列/sherda級別的會話(sticky),而不支持L4 HTTP平衡器。

7.4演員模型/「一鍵流」

對於關鍵單元(錢包):演員依次處理,其余並發由演員數處理。

7.5相等性+重新排序

即使恢復順序,重復也是可能的。將UPSERT按鍵+版本和Inbox結合起來(請參閱「Exactly-once vs At-least-once」)。


8)處理「有毒」信息(poison pills)

保持秩序面臨的挑戰是: 「如果一個消息不處理,如何生活?」

嚴格順序:鎖定密鑰流(SQS FIFO:整個組)。解決方案是按鍵DLQ:我們只將問題密鑰/組轉換為單獨的隊列/手動解析。
靈活順序:允許通行/賠償;我們計算並繼續(不適用於金融/關鍵總量)。
Retrais Policy:有限的「max-deliver」+backoff+avidemential效果。


9)多區域和全球系統

Cluster-linking/復制 (Kafka)不能保證跨區域的全球秩序。優先考慮局部按鍵順序和等效彎曲。
對於truly-global訂單,請使用音序器(中央日誌),但這會影響可用性(CAP:網絡中斷時減去A)。
另一種選擇:某些域(計數器、集合)的causal order+CRDT-不需要嚴格的順序。


10)順序可觀察性

Метрики: `out_of_order_total`, `reordered_in_window_total`, `late_events_total`, `buffer_size_current`, `blocked_keys_total`, `fifo_group_backlog`.

Логи: `key`, `seq`, `expected_seq`, `action=applybufferskipdlq`.
Tracing: spans 「order_key」、「partition」、「offset」、「seq」的屬性,指向復古。

11)反模式

一個隊列+許多不按鍵行駛的求和器-順序立即斷裂。
在沒有偶然性的情況下,通過筆式公共場所的回溯是雙打+順序。
「以防萬一」的全球秩序是潛伏期和成本的爆炸,沒有真正的好處。
SQS FIFO每個組都是完整的頭線。使用MessageGroupId按鍵。
忽略「熱鍵」-一個「錢包」會抑制一切;盡可能將密鑰分成副密鑰。
在單個隊列/組中混合關鍵流和布爾克流-相互影響和順序損失。


12)實施支票

  • 確定了保修級別:per-key/per-partition/causal/global?
  • 設計了針對「熱鍵」的排序密鑰和策略。
  • 已配置路由器:partization/MessageGroupId/ordering密鑰。
  • Concumers是通過密鑰隔離的(粘性路由,shard-workers).
  • 包括指針上的冪和/或Inbox/UPSERT。
  • 已實現sequence/version和reordering緩沖區(如果需要)。
  • DLQ by key和retrai with backoff.
  • 順序和異序度量:從順序開始,blocked_keys,late_events。
  • 遊戲日:重建,節點丟失,「有毒」消息,網絡延遲。
  • 文檔:順序不變性,窗口邊界,對SLA的影響。

13)配置示例

13.1 Kafka消費者(最小化秩序障礙)

properties max.poll.records=500 enable.auto.commit=false  # коммит после успешной обработки батча isolation.level=read_committed
💡 請確保一個用戶處理整個批次,並且您的操作是偶然的。

13.2 RabbitMQ(以並發為代價)

每個隊列一個concumer +'basic。qos(prefetch=1)`

對於並發-多隊列和hash-exchange:
bash rabbitmq-plugins enable rabbitmq_consistent_hash_exchange публикуем с хедером/ключом для консистентного хеша

13.3 SQS FIFO

設置MessageGroupId=key。並發=組數。
MessageDeduplicationId用於雙倍保護(在提供程序窗口中)。

13.4 NATS JetStream(ordered consumer,草圖)

bash nats consumer add ORDERS ORD-KEY-42 --filter "orders.42.>" --deliver pull \
--ack explicit --max-deliver 6
💡 請註意應用程序中的「sequence」和reordering緩沖區。

14) FAQ

問:我需要全球秩序嗎?
答:幾乎從來沒有。幾乎總是有足夠的按鍵。全球秩序-價格昂貴,並且影響了可用性。

問:如何以嚴格的順序使用「有毒」信息?
答:僅將其密鑰/組轉換為DLQ,其余部分繼續。

Q:可以同時獲得順序和比例嗎?
答:是的,按鍵順序+很多鍵/分期付款+在需要的地方進行偶數操作和重新排序緩沖。

問:更重要的是什麼:順序還是唯一的?
答:對於大多數域,按鍵+有效的異常效果(等效性/UPSERT)排序。運輸可以是空運。


15)結果

訂單是圍繞業務密鑰而不是昂貴的全球紀律的本地保證。設計密鑰和批次,限制「熱」密鑰,使用等效性,並在需要時使用sequence+reordering緩沖區。監視「出訂單」和「鎖定密鑰」指標,測試故障-並且在性能和可用性方面無需犧牲即可獲得可預測的處理。

Contact

與我們聯繫

如有任何問題或支援需求,歡迎隨時聯絡我們。我們隨時樂意提供協助!

開始整合

Email 為 必填。Telegram 或 WhatsApp 為 選填

您的姓名 選填
Email 選填
主旨 選填
訊息內容 選填
Telegram 選填
@
若您填寫 Telegram,我們將在 Email 之外,同步於 Telegram 回覆您。
WhatsApp 選填
格式:國碼 + 電話號碼(例如:+886XXXXXXXXX)。

按下此按鈕即表示您同意我們處理您的資料。