1. 程式人生 > 實用技巧 >訊息佇列RocketMQ(一)

訊息佇列RocketMQ(一)

訊息佇列RocketMQ(一)

訊息佇列應用分析

訊息佇列: 在訊息的傳輸過程中儲存訊息的容器,生產者和消費者不直接通訊,依靠佇列保證訊息的可靠性,避免訊息間的相互影響(例如避免雪崩)。

訊息佇列主要角色

服務端

客戶端

  1. 生產者(Consumer)

  2. 訂閱者(Producer)

應用場景

場景1

運用活動可能需要在業務邏輯中各個環節加入運營活動邏輯,而且有時效性,頻繁在正常業務邏輯中新增/刪除程式碼顯然不合理且風險極大。例如各種送紅包活動,有時效性,然後每次新增或者刪除這個活動我們都需要修改logic層的核心程式碼,如下圖的框架。

所以我們應對這種問題通常會引入一個MQ,不管使用者起什麼請求,logic都會發一個mq訊息,然後起一個運營的Business logic來消費訊息,他自己也有資料訪問層,訪問運用所用到的資料。這樣即使Business logic即使掛掉了也不影響核心邏輯。

場景2

核心基礎服務,可能各個業務線都會關注某些請求處理結果,不斷修改程式碼新增業務線的通知顯然不合理。

如下圖電商IM系統就實現了業務解耦。

訊息佇列的主要作用:

  1. 業務解耦:

將模組間的RPC呼叫改為通過訊息佇列中轉,解除系統間的耦合:提升系統穩定性,通過廣播訊息避免多次呼叫,提高編碼效率。

  1. 非同步呼叫(RPC非同步和MQ非同步不一樣,RPC非同步必須收到結果,MQ是純非同步,可以不需要結果):

對於無需關呼叫記過的場景可以通過訊息佇列非同步處理。

  1. 流量削峰:

系統的吞吐量往往取決於底層儲存服務的處理能力,資料訪問層可以調整消費速度緩解儲存服務壓力,避免短暫的高峰將系統壓垮。

例如:

我們可以很容易橫向拓展Logic和Data Access,而DB的擴充套件就非常困難(分庫分表,資料路由),制約效能的就是DB,所以需要MQ減少DB的壓力,也減少了對Logic的QPS需求。

思考:

使用訊息佇列能帶來很大的收益,但也會對系統架構造成一些負面影響(系統可用性,架構複雜度,排查問題路徑),訊息佇列不能完全代替rpc,需要合理設計業務呼叫。

高可用及高拓展解決方案剖析

RocketMQ功能特性:

支援事務型訊息

支援延時訊息

支援訊息重發

支援consumer端tag過濾

支援訊息回放(比如push出錯了沒有給使用者成功推送,我們就可以用訊息回放進行重新消費然後push)

RocketMQ拓撲圖:

Name Server(類似註冊中心)

Broker

Producer

Consumer

producer從name sever拉取特定topic的broker的路由資訊,然後producer就可以跟broker進行連線了,傳送訊息,consumer也是如此,指定特定的topic從name server拉去路由資訊,然後連線broker,消費特定topic的訊息。

通過增加broker即可分散式擴容。

consumer既連線Master又連線slave不是為了讀寫分離,而是為了可靠性,之後我會詳解。

RocketMQ架構

Broker主從部署,自身訊息註冊在NameServer中

Client從NameServer中獲取Broker資訊

NameServer節點相互獨立,無資料互動:

因為Broker數量少,所以我們不需要做NameServer間的資料同步,僅需要Broker給NameServer通過廣播的方式定時發心跳,然後就算一開始失敗,經過幾次心跳後也可以完成同步。

可靠性分析:

同步刷盤:效能低可靠性高。

非同步刷盤:效能高可靠性低。

非同步複製(主從):提高可靠性,不丟失效能。

同步雙寫(主從):可靠性最高,但犧牲效能。

官方文件關於可靠性的解釋:

RocketMQ支援訊息的高可靠,影響訊息可靠性的幾種情況:

  1. Broker非正常關閉
  2. Broker異常Crash
  3. OS Crash
  4. 機器掉電,但是能立即恢復供電情況
  5. 機器無法開機(可能是cpu、主機板、記憶體等關鍵裝置損壞)
  6. 磁碟裝置損壞

1)、2)、3)、4) 四種情況都屬於硬體資源可立即恢復情況,RocketMQ在這四種情況下能保證訊息不丟,或者丟失少量資料(依賴刷盤方式是同步還是非同步)。

5)、6)屬於單點故障,且無法恢復,一旦發生,在此單點上的訊息全部丟失。RocketMQ在這兩種情況下,通過非同步複製,可保證99%的訊息不丟,但是仍然會有極少量的訊息可能丟失。通過同步雙寫技術可以完全避免單點,同步雙寫勢必會影響效能,適合對訊息可靠性要求極高的場合,例如與Money相關的應用。注:RocketMQ從3.0版本開始支援同步雙寫。

可用性分析

主從模式Master宕機:

這個Broker就會變得可讀不可寫(Slave還可以被繼續消費)

叢集搭建方式:

  1. 單Master模式

  2. 多Master模式(一個Master掛了,可以訪問另一個Master,多Master也提高了儲存量和吞吐量)

  3. 多Master多Slave模式-非同步複製(提高了可靠性,一個Masker掛了後,Consumer可以繼續把這個Slave的訊息消費掉,然後Provider不在寫入這個掛掉的Master,改為寫入另一個master(比如兩個Master本來各處理provider的百分之50,現在一個掛了,沒掛的就處理百分之一百的))

  4. 多Master多Slave模式-同步雙寫

以上就是分散式方案(Mysql沒有路由模組,需要業務解決分散式問題,所以Mysql是一個單機資料庫)

RocketMQ儲存原理

CommitLog:儲存訊息主體(生產者的負載均衡將生產的訊息分配到ConsumeQueue中)

ConsumerQueue:訊息消費佇列(存的是在CommitLog裡的索引資訊,RocketMQ不丟訊息考的就是minOffset;Consumer可以一次拉去一批訊息,消費完後批量的會一批ACK,但也使RoketMQ有重複消費的問題,對於重複消費有嚴格要求的時候,我們需要做冪等處理)

IndexFile:訊息索引檔案

由RocketMQ的模型我們可以看到,RocketMQ有著順序寫隨機讀的問題。

優化手段

  1. CommitLog檔案切分,預設1G

  1. MMap提升檔案訪問效能(類似於零拷貝,我們讀寫一個檔案,我們會經歷使用者態到核心態的切換,實現Read和Write操作,例如我們讀的時候會先拷貝到核心空間,然後再拷貝到使用者空間,寫的時候也同理。MMap其實就是使用者態跟核心態進行了對映,我們操作使用者態的檔案實質是操作核心態的檔案,從而減少核心態和使用者態的資料交換。)

  2. SSD(機械硬碟實際上已經足夠)

生產方式

同步(sync)

非同步(async)

單向(oneway)

訊息消費由兩種方式:

Push:訊息佇列主動地將訊息推送給消費者(實時性高,但沒有考慮客戶端的消費能力)。

Pull:由消費者客戶端主動向訊息佇列拉取訊息(實時性低,可能造成大量無效請求)。

RocketMQ消費模式

RocketMQ地消費方式相當於拉模式,但是使用了長輪詢機制,來平衡Push和Pull地缺點

LongPoll:

  1. Consumer傳送拉去資訊

  2. Broker hold住請求,直到有新訊息再返回

  3. 請求超時,Consumer再次發起請求

  4. 請求超時預設三十秒

訊息消費方式

叢集消費:叢集內競爭消費,單條訊息只消費一次,各節點均勻消費Topic的訊息。

組廣播消費:各叢集消費全量的訊息,單條訊息在每個叢集都會被消費一次。

RocketMQ通常使用Group內競爭,Group間廣播對queue的訊息進行消費