1. 基礎概念
a. 消息模型「Message Model」
RocketMQ主要由Produce,Broker,Consumer三個部分組成,其中Producer負責生產消息,Consumer負責消費消息,Broker負責存儲消息,Broker在實際部署過程中對應的是一台服務器,每個Broker可以存儲多個Topic的消息,每個Topic也可以分片存儲在不同的Broker中,Message Queue用於存儲消息的物理地址,每個Topic中的消息可以存儲在多個Message Queue中,ConsumerGroup由多個Consumer組成
b. 消息生產者 [Producer]
負責生產消息,一般由業務系統負責生產消息,一個消息生產者會把業務系統中生產的消息發送到Broker服務器,Rocket提供了同步發送、異步發送、順序發送、單向發送等多種發送方式
c. 消息消費者 [Consumer]
負責消費消息,一般是後台系統異步消費,一個消息消費者會從Broker服務器拉取消息,並將其提供給應用程序,從用戶應用的角度而言提供了2種消費形式:拉取式消費、推動式消費
- 拉取式消費的應用會主動調用Consumer的拉消息方法從Broker服務器拉取消息
- 推動式消費模式下Broker收到數據後會主動推給消費端,該消費模式一般實時性較高
RocketMQ支持兩種消息模式:集群消費「Clustering」和廣播消費「Broadcasting」
- 集群消費模式下,相同Consumer Group的每個Consumer實例平均分攤消息
- 廣播消費模式下,相同Consumer Group的每個Consumer實例都接收全量的消息
d. 主題 [Topic]
表示一類消息的集合,每個主題包含若幹條消息,每個消息只能屬於一個主題,Topic是RocketMQ進行消息訂閱的基本單位
同一個Topic下的數據,會分片保存在不同的Broker上,而每一個分片單位,就叫做MessageQueue,MessageQueue是生產者發送消息和消費者消費消息的最小單位
e. 代理服務器 [Broker Server]
消息中轉角色,負責存儲消息、轉發消息,代理服務器在RocketMQ系統中負責接收從生產者發送來的消息並存儲,同時為消費者的拉取請求做準備,代理服務器也存儲消息相關的元數據,包括消費者組,消費進度偏移和主題等
Broker Server是RocketMQ的真正業務核心,包含了多個重要的子模塊:
- RemotingModule: 整個Broker的實體,負責處理來自clients端的請求
- Client Manager: 負責管理客戶端和維護Consumer的Topic訂閱消息
- Store Service: 提供方便簡單的API接口處理消息存儲到物理硬盤和查詢功能
- HA Service: 高可用服務,提供Master Broker和Slave Broker之間數據的同步
- Index Service: 根據特定的Message Key對投遞到Broker的消息進行索引服務,以提供消息的快速查詢
而Broker Server要保證高可用需要搭建主從集群架構,RocketMQ中有兩種Broker架構模式:
- 普通集群:會給每個節點分配一個固定的角色,master負責響應客戶端的請求,並存儲消息,slave則只負責對master的消息進行同步保存,並響應部分客戶端的讀請求,消息同步方式分為同步和異步,這個集群模式下的各個節點角色無法進行切換
- Dledger高可用集群:是RocketMQ自4.5版本引入後的視線高可用集群的一項技術,這個模式會隨機選出一個節點作為master,當master節點掛了之後,則會從slave中自動選出一個節點升級為master
- Dledger負責的事項
- 接管Broker的CommitLog消息存儲
- 從集群中選舉出master節點
- 完成master節點往slave節點的消息同步
- Dledger的master選舉使用的是Raft算法
- 每個節點有三個狀態,分別是Leader,Follower,Candidate,正常狀況下,集群中只會有Leader和Follower,Follower只會響應Leader和Candidate的響應,而所有來自客戶端的請求都會由Leader來處理,即便請求打到了Follower,也會轉發至Leader進行處理
- 集群剛啟動時,每個節點都會是follwer狀態,之後集群內部會發送一個timeout信號,所有follower會轉成candidate來拉取選票,獲得大多數選票的節點則會成為leader,其他候選人則轉變成follower,如果一個timeout信號發出時,沒有選出leader,將會重新開始一次新的選舉,而Leader節點會往其他節點發送心跳信號,確認它的Leader狀態
- 其他節點會啟動定時器,如果在指定時間內沒有收到Leader的心跳,則會轉為Candidate狀態,然後向其他成員發起投票請求,如果收到半數以上成員的投票,則Candidate會晉升為Leader,已有的Leader也有可能會退化成follower
- 在Raft協議中,會將時間分為一些任意時間長度的時間片段,叫做term,term會使用一個全局唯一,連續遞增的序號作為標識,起到的是邏輯時鐘的作用
- 在每個term的時間片中,都會進行新的選舉,每一個candidate都會努力爭取成為leader,獲得票數最多的節點就會被選舉為leader,成為leader的節點,在一個term時間片裡就會保持leader狀態,這樣,就會保證在同一時間段中,集群中只會有一個leader,在某些情況下,選票可能無法形成多數派,因此這個term可能到結束都無法選舉出leader,直到下一個term重新發起選舉,也就沒有了Zookeeper中腦裂的問題
- 每次選舉的過程中,每個節點都會存儲當前term編號,並在節點之間進行交流時,都會帶上自己的term編號,如果一個節點發現他的編號比另一個小,那則會將自己的term編號更新為較大的一個,而如果leader或candidate發現自己的編號不是最新的,它會自己轉成follower,如果接收到的請求term編號小於自己的編號,term將會拒絕執行
- 在選舉過程中,Raft協議會通過心跳機制來發起leader選舉,如果其他節點收到的是leader或candidate節點的RPC心跳確認,則會保持follower狀態,避免爭搶成為candidate,而leader會往其他節點發送心跳信號,來確認自己的地位,如果follower連續一段時間(2個timeout信號)內沒有收到來自leader的心跳,則會認為leader掛了,從而發起新一輪的選舉
- 選舉過程「3個節點的集群」
- 集群啟動時,三個節點都是follower,發起投票後,三個節點都會給自己投票,一輪投票結束後,三個節點的term都是1,因此選舉不出term
- 當一輪投票選舉不出leader後,三個節點會隨機進入隨機休眠,A休眠1秒,B休眠3秒,C休眠2秒
- 1秒後,A節點醒來,會把自己的term+1,同時給自己投一票,2秒時,C節點醒來,發現A的term已經為2,比自己term大,則承認A是leader,並同時把自己term+1,此時A已經獲得了集群中大多數選票,成為leader
- 到第3秒時,B節點醒來,同樣會承認A的term最大,自己的term也會更新為2,這樣集群中的所有candidate就都確認成了follower和leader
- 在這個任期內,A會不斷地發送心跳給另外2個節點,當A掛掉了之後,另外的節點沒有收到A的心跳,則會轉化為candidate的狀態,重新發起選舉
- 多副本的消息同步
- 簡單來說,數據同步會通過2個階段,一個uncommitted階段,一個commited階段
- Leader Broker上的Dledger收到一條數據後,會標記為uncommitted狀態,然後他會通過自己的DledgerServer組件把這個uncommitted數據發給Follower Broker的DledgerServer組件
- 接著Follower Broker的DledgerServer收到uncommitted消息之後,必須返回一個ack給Leader Broker的Deldger,然後如果Leader Broker收到超過半數的Follower Broker返回的ack之後,就會把消息標記為committed狀態
- Leader Broker上的DledgerServer就會發送committed消息給Follower broker上的DledgeServer,讓他們把消息也標記為committed狀態,基於Raft協議完成了兩階段的數據同步
- Dledger負責的事項
f. 名稱服務 [Name Server]
名稱服務充當路由消息的提供者,Broker Server會在啟動時向所有的Name Server註冊自己的服務信息,並且後續通過心跳的方式來保證這個服務中信息的實時性,生產者或消費者能夠通過名字服務查找各主題相應的Broker IP列表,多個NameServer實例組成集群,但相互獨立,無信息交換
這個特性意味著無需維護Name Server的負載均衡,只要有一台服務節點正常,整個路由服務就不會有影響
g. 消息 [Message]
消息系統所傳輸信息的物理載體,生產和消費數據的最小單位,每個消息必須屬於一個主題Topic,RocketMQ中每個消息擁有唯一的Message ID,且可以攜帶具有業務標識的Key,系統提供了通過Message ID和Key查詢消息的功能
Message上有一個消息設置的標誌,即Tag標籤,用於同一主題下區分不同類型的消息,來自同一業務單元的消息,可以根據不同業務目的在同一主題下設置不同標籤,標籤能夠有效地保持代碼的清晰度和連貫性,並優化RocketMQ提供的查詢系統,消費者可以根據Tag實現不同子主題的不同消費邏輯,實現更好的擴展性