訊息佇列RocketMQ(一)
訊息佇列RocketMQ(一)
訊息佇列應用分析
訊息佇列: 在訊息的傳輸過程中儲存訊息的容器,生產者和消費者不直接通訊,依靠佇列保證訊息的可靠性,避免訊息間的相互影響(例如避免雪崩)。
訊息佇列主要角色
服務端
客戶端
-
生產者(Consumer)
-
訂閱者(Producer)
應用場景
場景1
運用活動可能需要在業務邏輯中各個環節加入運營活動邏輯,而且有時效性,頻繁在正常業務邏輯中新增/刪除程式碼顯然不合理且風險極大。例如各種送紅包活動,有時效性,然後每次新增或者刪除這個活動我們都需要修改logic層的核心程式碼,如下圖的框架。
所以我們應對這種問題通常會引入一個MQ,不管使用者起什麼請求,logic都會發一個mq訊息,然後起一個運營的Business logic來消費訊息,他自己也有資料訪問層,訪問運用所用到的資料。這樣即使Business logic即使掛掉了也不影響核心邏輯。
場景2
核心基礎服務,可能各個業務線都會關注某些請求處理結果,不斷修改程式碼新增業務線的通知顯然不合理。
如下圖電商IM系統就實現了業務解耦。
訊息佇列的主要作用:
-
業務解耦:
將模組間的RPC呼叫改為通過訊息佇列中轉,解除系統間的耦合:提升系統穩定性,通過廣播訊息避免多次呼叫,提高編碼效率。
-
非同步呼叫(RPC非同步和MQ非同步不一樣,RPC非同步必須收到結果,MQ是純非同步,可以不需要結果):
對於無需關呼叫記過的場景可以通過訊息佇列非同步處理。
-
流量削峰:
系統的吞吐量往往取決於底層儲存服務的處理能力,資料訪問層可以調整消費速度緩解儲存服務壓力,避免短暫的高峰將系統壓垮。
例如:
我們可以很容易橫向拓展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支援訊息的高可靠,影響訊息可靠性的幾種情況:
- Broker非正常關閉
- Broker異常Crash
- OS Crash
- 機器掉電,但是能立即恢復供電情況
- 機器無法開機(可能是cpu、主機板、記憶體等關鍵裝置損壞)
- 磁碟裝置損壞
1)、2)、3)、4) 四種情況都屬於硬體資源可立即恢復情況,RocketMQ在這四種情況下能保證訊息不丟,或者丟失少量資料(依賴刷盤方式是同步還是非同步)。
5)、6)屬於單點故障,且無法恢復,一旦發生,在此單點上的訊息全部丟失。RocketMQ在這兩種情況下,通過非同步複製,可保證99%的訊息不丟,但是仍然會有極少量的訊息可能丟失。通過同步雙寫技術可以完全避免單點,同步雙寫勢必會影響效能,適合對訊息可靠性要求極高的場合,例如與Money相關的應用。注:RocketMQ從3.0版本開始支援同步雙寫。
可用性分析
主從模式Master宕機:
這個Broker就會變得可讀不可寫(Slave還可以被繼續消費)
叢集搭建方式:
-
單Master模式
-
多Master模式(一個Master掛了,可以訪問另一個Master,多Master也提高了儲存量和吞吐量)
-
多Master多Slave模式-非同步複製(提高了可靠性,一個Masker掛了後,Consumer可以繼續把這個Slave的訊息消費掉,然後Provider不在寫入這個掛掉的Master,改為寫入另一個master(比如兩個Master本來各處理provider的百分之50,現在一個掛了,沒掛的就處理百分之一百的))
-
多Master多Slave模式-同步雙寫
以上就是分散式方案(Mysql沒有路由模組,需要業務解決分散式問題,所以Mysql是一個單機資料庫)
RocketMQ儲存原理
CommitLog:儲存訊息主體(生產者的負載均衡將生產的訊息分配到ConsumeQueue中)
ConsumerQueue:訊息消費佇列(存的是在CommitLog裡的索引資訊,RocketMQ不丟訊息考的就是minOffset;Consumer可以一次拉去一批訊息,消費完後批量的會一批ACK,但也使RoketMQ有重複消費的問題,對於重複消費有嚴格要求的時候,我們需要做冪等處理)
IndexFile:訊息索引檔案
由RocketMQ的模型我們可以看到,RocketMQ有著順序寫隨機讀的問題。
優化手段:
-
CommitLog檔案切分,預設1G
-
MMap提升檔案訪問效能(類似於零拷貝,我們讀寫一個檔案,我們會經歷使用者態到核心態的切換,實現Read和Write操作,例如我們讀的時候會先拷貝到核心空間,然後再拷貝到使用者空間,寫的時候也同理。MMap其實就是使用者態跟核心態進行了對映,我們操作使用者態的檔案實質是操作核心態的檔案,從而減少核心態和使用者態的資料交換。)
-
SSD(機械硬碟實際上已經足夠)
生產方式:
同步(sync)
非同步(async)
單向(oneway)
訊息消費由兩種方式:
Push:訊息佇列主動地將訊息推送給消費者(實時性高,但沒有考慮客戶端的消費能力)。
Pull:由消費者客戶端主動向訊息佇列拉取訊息(實時性低,可能造成大量無效請求)。
RocketMQ消費模式:
RocketMQ地消費方式相當於拉模式,但是使用了長輪詢機制,來平衡Push和Pull地缺點
LongPoll:
-
Consumer傳送拉去資訊
-
Broker hold住請求,直到有新訊息再返回
-
請求超時,Consumer再次發起請求
-
請求超時預設三十秒
訊息消費方式:
叢集消費:叢集內競爭消費,單條訊息只消費一次,各節點均勻消費Topic的訊息。
組廣播消費:各叢集消費全量的訊息,單條訊息在每個叢集都會被消費一次。
RocketMQ通常使用Group內競爭,Group間廣播對queue的訊息進行消費