1. 程式人生 > >訊息佇列高可用設計

訊息佇列高可用設計

常用的訊息佇列的高可用是怎麼設計的呢?

訊息佇列一般都有一個nameserver服務,用來檢測broker是否存活,或者處理能力上是否存在延遲。這樣在傳送訊息時就可以規避將訊息傳送到宕機的broker上,也避免因為網路等原因訊息處理失敗。

那麼針對於以上兩種情況,訊息佇列如何保證高可用方案的呢?

重試

訊息傳送時,一般存在這樣的方法:

for(; times < timesTotal; times++){
// send message
}

這裡是client傳送訊息時決定的重試次數,預設值為3。重試可以提高訊息傳送的成功率。

訊息傳送

預設的訊息傳送採用對訊息佇列進行取模,確定佇列。 其他的方式比如輪訓方式等。

Kafka 有兩個預設的分配策略:

  • Range:該策略會把主題的若干個連續的分割槽分配給消費者。
  • RoundRobin:該策略把主題的所有分割槽逐個分配給消費者。

消費者

消費者向kafka訂閱topic,並從topic上接收訊息。

消費者屬於消費者組,一個消費組的消費組訂閱的是同一個topic,每個消費者接收topic一個partition的訊息。

1個消費者接收4個分割槽的訊息:

2個消費者接收4個分割槽的訊息:

4個消費者接收4個分割槽的訊息:

5個消費者接收4個分割槽的訊息:

如果消費者群組的消費者超過主題的分割槽數量,那麼有一部分消費者就會被閒置,不會接收到任何訊息。

兩個消費者群組對應一個主題:

當一個消費者被關閉或發生崩潰時,它就離開群組,原本由它讀取的分割槽將由群組裡的其他消費者來讀取。分割槽的所有權從一個消費者轉移到另一個消費者,這樣的行為被稱為再均衡。在再均衡期間,消費者無法讀取訊息,造成整個群組一小段時間的不可用。

通過上面消費者例項數量變化思考一個問題。在消費者機器重啟過程中,存在partition和消費者重新建立聯絡的情況,比如最開始有4個消費者,由於並行重啟消費者,可能存在一段時間消費者數量變為2個,當重啟完成後消費者數量有變成了4個。

這個過程存在訊息可能重複傳送到同一個消費者消費的情況,造成重複消費,如果是對訊息重複敏感的應用場景,我司自研的訊息佇列元件會提供一個選項,訊息在分割槽進行主動積壓,預設積壓30s等待消費者重啟完成,達到穩定的消費者數量。

消費者通過向被指派為群組協調器的 broker 傳送心跳來維持它們和群組的從屬關係以及它們對分割槽的所有權關係。消費者會在輪訓訊息或提交偏移量時傳送心跳。如果消費者停止傳送心跳的時間足夠長,會話就會過期,群組協調器認為它已經死亡,就會觸發一次再均衡。

如果一個消費者發生崩潰,並停止讀取訊息,群組協調器會等待幾秒鐘,確認它死亡了才會觸發再均衡。所以上面的延遲是由於再平衡期間不可用造成的。

當消費者要加入群組時,它會向群組協調器傳送一個 JoinGroup 請求。

第一個加入群組的消費者將成為"群主"。群主從協調器那裡獲得群組的成員列表,並負責給每一個消費者分配分割槽。 分配完畢之後,群主把分配情況列表傳送給群組協調器,協調器再把這些資訊傳送給所有消費者。 每個消費者只能看到自己的分配情況。這個過程會在每次再均衡時重複發生。

訊息消費

kafka消費者有自己消費偏移量,這個偏移量是從kafka中讀取的量,和kafka提交的偏移量不一樣。消費者一般需要第一次和rebalance的時候需要根據提交的偏移量來獲取資料,剩下的時候根據自己本地的偏移量來獲取。

當消費者使用了自動提交模式,當還沒有提交的時候,有消費者加入或者移除,傳送rebalance,再次消費時,消費者根據提交偏移量進行,可能產生