Apache RocketMQ 基礎概念及架構解析
Apache RocketMQ 系列:
Apache RocketMQ之JMS基本概念及使用:http://www.lxweimin.com/p/d2e3fd77c4f4
Apache RocketMQ 基礎概念及架構解析:http://www.lxweimin.com/p/95ab928960b3
Apache RocketMQ 的基礎特性介紹:http://www.lxweimin.com/p/570680b32590
Apache RocketMQ 集群搭建(兩主兩從):http://www.lxweimin.com/p/b090138cf52c
Apache RocketMQ 刷盤策略與復制策略: http://www.lxweimin.com/p/d66b381428bb
優秀博客:
https://blog.csdn.net/BtB5e6Nsu1g511Eg5XEg/article/details/83828893
https://blog.csdn.net/GV7lZB0y87u7C/article/details/78382605
https://blog.csdn.net/qq_34021712/article/details/78169014
https://blog.csdn.net/babyupup/article/details/72642571
http://www.lxweimin.com/p/f90b0f175e2d
本文主要介紹:
一、RocketMQ起源
二、RocketMQ的概念模型
三、RocketMQ的存儲模型
四、RocketMQ的部署模型
五、RocketMQ最佳實踐總結 (后面介紹)
一、RocketMQ的起源
通常,每個產品的誕生都源于一個具體的需求或問題,RocketMQ也不例外。起初,產品的原型像一個巨石,把所有需要實現的程序和接口都羅列到一起。但隨著公司業務的發展,所有的系統和功能都在這個巨石上開發,當覆蓋幾百上千名開發人員的時候,瓶頸就出來了。這時候,就需要我們把系統進行分解。
分解后,就出現了上圖中的分布式架構,這類架構最大的特點就是解耦,而RocketMQ的異步解耦意味著底層的重構不會影響到上層應用的功能。RocketMQ另一個優勢是削峰填谷,在面臨流量的不確定性時,實現對流量的緩沖處理。此外,RocketMQ的順序設計特性使得RocketMQ成為一個天然的排隊引擎,例如,三個應用同時對一個后臺引擎發起請求,排隊引擎的特性可以確保不會引起“撞車”事故。
總結:RocketMQ的作用(消息中間件):解耦、削峰填谷、高并發,或者說:異步消息處理、高性能(高并發讀寫)、高可用(主備)、可伸縮(削峰填谷)、最終一致性。
補充:
在2007年的時候,淘寶實施了“五彩石”項目,“五彩石”用于將交易系統從單機變成分布式,也是在這個過程中產生了阿里巴巴第一代消息引擎——Notify。
在2010年的時候,阿里巴巴B2B部門基于ActiveMQ的5.1版本也開發了自己的一款消息引擎,稱為Napoli,這款消息引擎在B2B里面廣泛地被使用,不僅僅是在交易領域,在很多的后臺異步解耦等方面也得到了廣泛的應用。
在2011年的時候,業界出現了現在被很多大數據領域所推崇的Kafka消息引擎,阿里巴巴在研究了Kafka的整體機制和架構設計之后,基于Kafka的設計使用Java進行了完全重寫并推出了MetaQ 1.0版本,主要是用于解決順序消息和海量堆積的問題。
在2012年,阿里巴巴對于MetaQ進行了架構重組升級,開發出了MetaQ 2.0,這時就發現MetaQ原本基于Kafka的架構在阿里巴巴如此龐大的體系下很難進行水平擴展,所以在2012年的時候就開發了RocketMQ 3.0版本。很多人會問到RocketMQ 3.0和MetaQ 3.0的區別,其實這兩者是等價的版本,只不過阿里內部使用的稱為MetaQ 3.0,外部開源稱之為RocketMQ 3.0。
在2015年,又基于RocketMQ開發了阿里云上的Aliware MQ和Notify 3.0。
在2016年的時候,阿里巴巴將RocketMQ的內核引擎捐贈給了Apache基金會。
以上就是RocketMQ的整體發展歷史,其實在阿里巴巴內部圍繞著RocketMQ內核打造了三款產品,分別是MetaQ、Notify和Aliware MQ。這三者分別采用了不同的模型,MetaQ主要使用了拉模型,解決了順序消息和海量堆積問題;Notify主要使用了推模型,解決了事務消息;而云產品Aliware MQ則是提供了商業化的版本。
二、RocketMQ的概念模型
對于任何一款中間件產品而言,清晰的概念模型是幫助開發者正確理解使用它的關鍵。從RocketMQ的概念模型來看:Topic是用于存儲邏輯的地址的,Producer是信息的發送,Consumer是信息的接收者。
這只是一個基礎的概念模型,在實際的生產中,結構會更復雜,例如我們需要對中間的Topic進行分區,出現多個有關聯的Topic,再如同一個信息的發送方會有多個訂閱者,同一個需求方會有多個發送方,出現一對多、多對一的情況。
上圖就是對Topic、Producer、Consumer擴展后的概念模型。RocketMQ中可以接觸到的所有概念都可以在這個概念模型圖中找到。
左邊有兩個Producer,中間就是兩個分布式的Topic,用于存儲邏輯地址的兩個Topic中分別有兩個用于存儲物理存儲地址的Message Queue,Broker是實際部署過程的對應的一臺設備,右邊則是兩個Consumer,Consumer Group是代表兩個Consumer可共享相互之間的訂閱。不同的Consumer Group相互獨立。
一句話總結就是不同的Group是廣播訂閱的,同一個Group則是負載訂閱的。圖中的連線表示各模塊之間的關系,例如Consumer Group A中的Consumer1對應著Message Queue0和Message Queue1的兩個隊列,分布在BrokerA這一臺設備上。
補充:
Producer Group:
用來表示一個収送消息應用,一個 Producer Group 下包含多個 Producer 實例,可以是多臺機器,也可以 是一臺機器的多個迕程,戒者一個迕程的多個 Producer 對象。一個 Producer Group 可以収送多個 Topic 消息,Producer Group 作用如下:
- 標識一類 Producer
- 可以通過運維工具查詢返個収送消息應用下有多個 Producer 實例
- 収送分布式事務消息時,如果 Producer 中途意外宕機,Broker 會主勱回調 Producer Group 內的任意一臺機器來確訃事務狀態
Consumer Group:
用來表示一個消費消息應用,一個 Consumer Group 下包含多個 Consumer 實例,可以是多臺機器,也可
以是多個迕程,戒者是一個迕程的多個 Consumer 對象。一個 Consumer Group 下的多個 Consumer 以均攤
方式消費消息,如果設置為廣播方式,那舉返個 Consumer Group 下的每個實例都消費全量數據。
Topoic:消息的邏輯管理單位。
Message Queue:消息的物理管理單位。一個Topic下可以有多個Queue,Queue的引入使得消息存儲可以分布式集群化,具有了水平擴展的能力。
順序消息:用戶實現MessageQueueSelector為某一批消息(通常是有同樣的唯一的標示ID),選擇同一個Queue,則這一批消息的消費將是順序消費(并由同一個consumer完成消費)。
事務消息:這樣的消息有多個狀態,并且其發送是兩階段的。第一個階段發送PREPARED狀態的消息,此時consumer是看不見這種狀態的消息的,發送完畢后回調用戶的TransactionExecutor接口,執行相應的事務操作(如數據庫),當事務操作成功時,則對此條消息返回commit,讓broker對該消息執行commit操作,成為commit狀態的消息對consumer是可見的。
三、RocketMQ的存儲模
RocketMQ的消息的存儲是由ConsumeQueue和CommitLog 配合來完成的,ConsumeQueue中只存儲很少的數據,消息主體都是通過CommitLog來進行讀寫。
CommitLog:
是消息主體以及元數據的存儲主體,對CommitLog建立一個ConsumeQueue,每個ConsumeQueue對應一個(概念模型中的)MessageQueue,所以只要有Commit Log在,Consume Queue即使數據丟失,仍然可以恢復出來。
Consume Queue:
是一個消息的邏輯隊列,存儲了這個Queue在CommitLog中的起始offset,log大小和MessageTag的hashCode。每個Topic下的每個Queue都有一個對應的ConsumerQueue文件,例如Topic中有三個隊列,每個隊列中的消息索引都會有一個編號,編號從0開始,往上遞增。并由此一個位點offset的概念,有了這個概念,就可以對Consumer端的消費情況進行隊列定義。
補充:
RocketMQ的broker端,不負責推送消息,無論消費者是否消費消息,都將消息存儲起來。誰要消費消息,就向broker發請求獲取消息,消費記錄由consumer來維護。RocketMQ提供了兩種存儲方式來保留消費記錄:一種是保留在consumer所在的服務器上;另一種是保存在broker服務器上。用戶還可以自己實現相應的消費進度存儲接口。
默認情況下,采用集群消費(CLUSTERING),會將記錄保存在broker端;而采用廣播消費(BROADCASTING)則會將消費記錄保存在本地。
RocketMQ以Topic來管理不同應用的消息。對于生產者而言,發送消息是,需要指定消息的Topic,對于消費者而言,在啟動后,需要訂閱相應的Topic,然后可以消費相應的消息。Topic是邏輯上的概念,在物理實現上,一個Topic由多個Queue組成,采用多個Queue的好處是可以將Broker存儲分布式化,提高系統性能。
RocketMQ中,producer將消息發送給Broker時,需要制定發送到哪一個隊列中,默認情況下,producer會輪詢的將消息發送到每個隊列中(所有broker下的Queue合并成一個List去輪詢)。
對于consumer而言,會為每個consumer分配固定的隊列(如果隊列總數沒有發生變化),consumer從固定的隊列中去拉取沒有消費的消息進行處理。
RocketMQ 存儲特點:
零拷貝原理:Consumer 消費消息過程,使用了零拷貝,零拷貝包含以下兩種方式:
- 使用 mmap + write 方式
優點:即使頻繁調用,使用小塊文件傳輸,效率也很高
缺點:不能很好的利用 DMA 方式,會比 sendfile 多消耗CPU,內存安全性控制復雜,需要避免 JVM Crash 問題。
- 使用 sendfile 方式
優點:可以利用 DMA 方式,消耗 CPU 較少,大塊文件傳輸效率高,無內存安全新問題。
缺點:小塊文件效率低亍 mmap 方式,只能是 BIO 方式傳輸,不能使用 NIO。
RocketMQ 選擇了第一種方式,mmap+write 方式,因為有小塊數據傳輸的需求,效果會比 sendfile 更好。
RocketMQ 文件系統:
RocketMQ 選擇 Linux Ext4 文件系統。
原因如下:
Ext4 文件系統刪除 1G 大小的文件通常耗時小亍 50ms,而 Ext3 文件系統耗時約 1s 左右,且刪除文件時,磁盤 IO 壓力極大,會導致 IO 寫入超時。
文件系統局面需要做以下調優措施: 文件系統 IO 調度算法需要調整為 deadline,因為 deadline 算法在隨機讀情況下,可以合幵讀請求為順序跳躍
方式,從而提高讀 IO 吞吐量。
RocketMQ 數據存儲結構:
RocketMQ 存儲目錄結構
|-- abort
|-- checkpoint
|-- config
| |-- consumerOffset.json
| |-- consumerOffset.json.bak
| |-- delayOffset.json
| |-- delayOffset.json.bak
| |-- subscriptionGroup.json.bak
| |-- topics.json
| |-- topics.json.bak
|-- commitlog
| |-- 00000003384434229248
| |-- 000000033855079710
| |-- 0000000338658171289
|-- consumequeue
|-- %DLQ%ConsumerGroupA
| |-- 0
| | |-- 00000000000006000000
|-- %RETRY%ConsumerGroupA
| |-- 0
| | |-- 00000000000000000000
|-- %RETRY%ConsumerGroupB
| |-- 0
| | |-- 00000000000000000000
|-- SCHEDULE_TOPIC_XXXX
| |-- 2
| | |-- 00000000000006000000
| |-- 3
| | |-- 00000000000006000000
|-- TopicA
| |-- 0
| | |-- 00000000002604000000
| | |-- 00000000002610000000
| | |-- 00000000002616000000
| |-- 1
| | |-- 00000000002610000000
| | |-- 00000000002610000000
|-- TopicB
| |-- 0
| | |-- 00000000000732000000
| |-- 1
| | |-- 00000000000732000000
| |-- 2
| | |-- 00000000000732000000
四、RocketMQ的部署模型
在實際的部署過程中,Broker是實際存儲消息的數據節點,Nameserver則是服務發現節點,Producer發送消息到某一個Topic,并給到某個Consumer用于消費的過程中,需要先請求Nameserver拿到這個Topic的路由信息,即Topic在哪些Broker上有,每個Broker上有哪些隊列,拿到這些請求后再把消息發送到Broker中;相對的,Consumer在消費的時候,也會經歷這個流程。
補充:
NameServer:
NameServer是一個幾乎無狀態節點,可集群部署,節點之間無任何信息同步(類似ZK)。
NameServer用于存儲Topic、Broker關系信息,功能簡單,穩定性高。多個NameServer之間相互沒有通信,單臺NameServer宕機不影響其他NameServer與集群;即使整個NameServer集群宕機,已經正常工作的Producer,Consumer,Broker仍然能正常工作,但新起的Producer, Consumer,Broker就無法工作。
NameServer壓力不會太大,平時主要開銷是在維持心跳和提供Topic-Broker的關系數據。但有一點需要注意,Broker向NameServer發心跳時,會帶上當前自己所負責的所有Topic信息,如果Topic個數太多(萬級別),會導致一次心跳中,就Topic的數據就幾十M,網絡情況差的話,網絡傳輸失敗,心跳失敗,導致NameServer誤認為Broker心跳失敗。
Broker :
Broker 部署相對復雜,Broker分為Master 與 Slave,一個Master可以對應多個 Slave,但是一個Slave只能對應一個Master。
Master 與 Slave 的對應關系通過指定相同的BrokerName,不同的 BrokerId 來定義,BrokerId為0表示Master,非 0 表示 Slave。
Master可以部署多個。每個Broker與NameServer 集群中的所有節點建立長連接,定時注冊Topic信息到所有NameServer。
Producer與NameServer集群中的其中一個節點(隨機選擇)建立長連接,定期從 Name Server 取 Topic 路由信息,并向提供 Topic 服務的 Master 建立長連接,且定時向 Master 發送心跳。
Producer :
Producer 完全無狀態,可集群部署。
Producer啟動時,也需要指定NameServer的地址,從NameServer集群中選一臺建立長連接。如果該NameServer宕機,會自動連其他NameServer。直到有可用的NameServer為止。
Producer每30秒從NameServer獲取Topic跟Broker的映射關系,更新到本地內存中。再跟Topic涉及的所有Broker建立長連接,每隔30秒發一次心跳。在Broker端也會每10秒掃描一次當前注冊的Producer,如果發現某個Producer超過2分鐘都沒有發心跳,則斷開連接。
Producer發送時,會自動輪詢當前所有可發送的broker,一條消息發送成功,下次換另外一個broker發送,以達到消息平均落到所有的broker上。
假如某個Broker宕機,意味生產者最長需要30秒才能感知到。在這期間會向宕機的Broker發送消息。當一條消息發送到某個Broker失敗后,會往該broker自動再重發2次,假如還是發送失敗,則拋出發送失敗異常。業務捕獲異常,重新發送即可。客戶端里會自動輪詢另外一個Broker重新發送,這個對于用戶是透明的。
Consumer:
Consumer與NameServer集群中的其中一個節點(隨機選擇)建立長連接,定期從NameServer取Topic路由信息,并向提供Topic服務的Master、Slave建立長連接,且定時向 Master、Slave發送心跳。
Consumer既可以從Master訂閱消息,也可以從 Slave 訂閱消息,訂閱規則由 Broker 配置決定。
Consumer啟動時需要指定NameServer地址,與其中一個NameServer建立長連接。消費者每隔30秒從NameServer獲取所有Topic的最新隊列情況,這意味著某個Broker如果宕機,客戶端最多要30秒才能感知。連接建立后,從NameServer中獲取當前消費Topic所涉及的Broker,直連Broker。
Consumer跟Broker是長連接,會每隔30秒發心跳信息到Broker。Broker端每10秒檢查一次當前存活的Consumer,若發現某個Consumer 2分鐘內沒有心跳,就斷開與該Consumer的連接,并且向該消費組的其他實例發送通知,觸發該Consumer集群的負載均衡。
Consumer有兩種模式消費:集群消費,廣播消費。
廣播消費:每個消費者消費Topic下的所有隊列。
集群消費:一個topic可以由同一個ID下所有消費者分擔消費。
五、RocketMQ最佳實踐總結
Apache RocketMQ 集群搭建(兩主兩從):http://www.lxweimin.com/p/b090138cf52c