消息隊列如何確保消息的有序性?

要想實現消息有序,須要從 Producer 和 Consumer 兩方面來考慮。多線程

首先,Producer 生產消息的時候就必需要有序。架構

而後,Consumer 消費的時候,也要按順序來,不能亂。spa

Producer 有序

像 RabbitMQ 這類普通的消息系統,隊列結構簡單,Producer 向隊列中發送消息就完了,進入隊列的消息確定是有序的。線程

Kafka 比較特殊,由於它的一個 Topic(就是隊列的概念)實際上分爲了多個 Partition。設計

Producer 發送消息的時候,是分散在不一樣 Partition 的。3d

Producer 按順序發消息,但進入 Kafka Topic 以後,這些消息就不必定進到哪一個 Partition 了,因此順序確定是亂的。token

若是想 Topic 內的消息全局有序,就只能設置一個 Partition 了,這就變成了 RabbitMQ 那種結構。隊列

但這種結構不符合 Kafka 的設計理念,Topic 只有一個 Partition 就失去了擴展性。內存

kafka 還支持一種局部有序的方式,就是把某一類的消息都放入同一個 Partition,就保證了這組消息的順序。開發

在發消息的時候指定 Partition Key,Kafka 對其進行 Hash 計算,根據計算結果決定放入哪一個 Partition。

因此,Partition Key 同樣的消息確定是在一塊兒的。

例如使用用戶 ID 作 key,這樣同一個用戶的消息確定是在一塊兒的,就保證了這一組的消息的有序。

Consumer 有序

MQ 內消息有序,那麼 Consumer 天然也是按順序接收的。

可是,若是使用了多個 Consumer,就可能出現亂序。

例如 RabbitMQ 的一個 Queue 有 3個 Consumer,雖然會按順序接收到消息,可是它們各自的處理速度是不一樣的,因此,出來的結果極可能是亂序的。

若是想嚴格按順序來,就只能使用一個 Consumer。

若是可使用局部有序,那麼就把以前的一個隊列拆爲多個隊列,就像 Kafka 的 Partition Key 同樣,把同組數據放入同一個隊列。

Kafka 中一個 Partition 只能對應一個 Consumer,但若是 Consumer 使用了多線程,就和多個 Consumer 一個效果了,仍是會形成亂序。

這樣的話就須要進一步細化消息的分組。

爲每一個線程建立一個內存隊列,Consumer 收到消息後,把同組的消息都放在同一個內存隊列,由同一個線程處理便可。

小結一下,消息的有序須要 Producer 和 Consumer 都有序。

RabbitMQ 的隊列結構簡單,Producer 發送的消息是有序的。但 Kafka 特殊,一個 Topic 有多個 Partition,若是要求全局有序,就只能使用一個 Partition。

若是能夠接受局部有序,就能夠爲消息設置 Partition Key,其 Hash 計算結果相同的消息都會在同一個 Partition。

Consumer 消費時須要注意多 Consumer 的狀況,例如多個消費線程。

能夠在 Consumer 收到消息後再細化分組,同組的消息交給同一個消費線程處理。

推薦閱讀

OAuth2 圖解

輕鬆理解 Kubernetes 的核心概念

開發者必需要了解的架構技術趨勢:Service Mesh

相關文章
相關標籤/搜索