前言
初步接觸了RocketMQ后發(fā)現(xiàn)其與傳統(tǒng)意義上的實(shí)現(xiàn)JMS協(xié)議的消息隊(duì)列(如ActiveMQ)存在著不小的區(qū)別,很有必要對(duì)其中的一些概念做個(gè)說(shuō)明。
部署架構(gòu)

如圖所示為RocketMQ基本的部署結(jié)構(gòu),主要分為NameServer集群、Broker集群、Producer集群和Consumer集群四個(gè)部分。
NameServer集群
NameServer的作用是注冊(cè)中心,類(lèi)似于Zookeeper,但又有區(qū)別于它的地方。每個(gè)NameServer節(jié)點(diǎn)互相之間是獨(dú)立的,沒(méi)有任何信息交互,也就不存在任何的選主或者主從切換之類(lèi)的問(wèn)題,因此NameServer與Zookeeper相比更輕量級(jí)。單個(gè)NameServer節(jié)點(diǎn)中存儲(chǔ)了活躍的Broker列表(包括master和slave),這里活躍的定義是與NameServer保持有心跳。
Broker集群
Broker是具體提供業(yè)務(wù)的服務(wù)器,單個(gè)Broker節(jié)點(diǎn)與所有的NameServer節(jié)點(diǎn)保持長(zhǎng)連接及心跳,并會(huì)定時(shí)將Topic信息注冊(cè)到NameServer,順帶一提底層的通信和連接都是基于Netty實(shí)現(xiàn)的。
Broker中分master和slave兩種角色,每個(gè)master可以對(duì)應(yīng)多個(gè)slave,但一個(gè)slave只能對(duì)應(yīng)一個(gè)master,master和slave通過(guò)指定相同的Brokername,不同的BrokerId (master為0)成為一個(gè)組。master和slave之間的同步方式分為同步雙寫(xiě)和異步復(fù)制,異步復(fù)制方式master和slave之間雖然會(huì)存在少量的延遲,但性能較同步雙寫(xiě)方式要高出10%左右。
另外,Broker中還存在一些非常重要的名詞需要說(shuō)明:
- Topic和Queue
RocketMQ的Topic/Queue和JMS中的Topic/Queue概念有一定的差異,JMS中所有消費(fèi)者都會(huì)消費(fèi)一個(gè)Topic消息的副本,而Queue中消息只會(huì)被一個(gè)消費(fèi)者消費(fèi);但到了RocketMQ中Topic只代表普通的消息隊(duì)列,而Queue是組成Topic的更小單元,集群消費(fèi)模式下一個(gè)消費(fèi)者只消費(fèi)該Topic中部分Queue中的消息,當(dāng)一個(gè)消費(fèi)者開(kāi)啟廣播模式時(shí)則會(huì)消費(fèi)該Topic下所有Queue中的消息。Topic和Queue的具體關(guān)系可以參考下圖

- Tags
Tags是Topic下的次級(jí)消息類(lèi)型(注:Tags也支持TagA || TagB這樣的表達(dá)式),可以在同一個(gè)Topic下基于Tags進(jìn)行消息過(guò)濾。Tags的過(guò)濾需要經(jīng)過(guò)兩次比對(duì),首先會(huì)在Broker端通過(guò)Tag hashcode進(jìn)行一次比對(duì)過(guò)濾,匹配成功傳到consumer端后再對(duì)具體Tags進(jìn)行比對(duì),以防止Tag hashcode重復(fù)的情況。Queue中具體的存儲(chǔ)單元結(jié)構(gòu)如下圖:

Producer集群
- 與nameserver的關(guān)系
單個(gè)Producer和一臺(tái)nameserver保持長(zhǎng)連接,定時(shí)查詢(xún)topic配置信息,如果該nameserver掛掉,生產(chǎn)者會(huì)自動(dòng)連接下一個(gè)nameserver,直到有可用連接為止,并能自動(dòng)重連。與nameserver之間沒(méi)有心跳。
- 與broker的關(guān)系
單個(gè)Producer和與其關(guān)聯(lián)的所有broker保持長(zhǎng)連接,并維持心跳。默認(rèn)情況下消息發(fā)送采用輪詢(xún)方式,會(huì)均勻發(fā)到對(duì)應(yīng)Topic的所有queue中。
- 最佳實(shí)踐
- 一個(gè)應(yīng)用盡可能只使用一個(gè) Topic,消息子類(lèi)型用 tags 來(lái)標(biāo)識(shí),tags 可以由應(yīng)用自由設(shè)置。只有發(fā)送消息設(shè)置了tags,消費(fèi)方在訂閱消息時(shí),才可以利用 tags 在 broker 做消息過(guò)濾。
- 每個(gè)消息在業(yè)務(wù)層面的唯一標(biāo)識(shí)碼,要設(shè)置到 keys 字段,方便將來(lái)定位消息丟失問(wèn)題。服務(wù)器會(huì)為每個(gè)消
息創(chuàng)建索引(哈希索引),應(yīng)用可以通過(guò) Topic,key 來(lái)查詢(xún)返條消息內(nèi)容,以及消息被誰(shuí)消費(fèi)。由于是哈希索引,請(qǐng)務(wù)必保證 key 盡可能唯一,這樣可以避免潛在的哈希沖突。 - 消息發(fā)送成功或者失敗,要打印消息日志,務(wù)必要打印 sendresult 和 key 字段。
- 對(duì)于消息不可丟失應(yīng)用,務(wù)必要有消息重發(fā)機(jī)制。例如:消息發(fā)送失敗,存儲(chǔ)到數(shù)據(jù)庫(kù),能有定時(shí)程序嘗試重發(fā)或者人工觸發(fā)重發(fā)。
- 某些應(yīng)用如果不關(guān)注消息是否發(fā)送成功,請(qǐng)直接使用
sendOneWay方法發(fā)送消息。
Consumer集群
- 與nameserver的關(guān)系
單個(gè)Consumer和一臺(tái)nameserver保持長(zhǎng)連接,定時(shí)查詢(xún)topic配置信息,如果該nameserver掛掉,消費(fèi)者會(huì)自動(dòng)連接下一個(gè)nameserver,直到有可用連接為止,并能自動(dòng)重連。與nameserver之間沒(méi)有心跳。
- 與broker的關(guān)系
單個(gè)Consumer和與其關(guān)聯(lián)的所有broker保持長(zhǎng)連接,并維持心跳,失去心跳后,則關(guān)閉連接,并向該消費(fèi)者分組的所有消費(fèi)者發(fā)出通知,分組內(nèi)消費(fèi)者重新分配隊(duì)列繼續(xù)消費(fèi)。
- 最佳實(shí)踐
- Consumer 數(shù)量要小于等于queue的總數(shù)量,由于Topic下的queue會(huì)被相對(duì)均勻的分配給Consumer,如果 Consumer 超過(guò)queue的數(shù)量,那多余的 Consumer 將沒(méi)有queue可以消費(fèi)消息。
- 消費(fèi)過(guò)程要做到冪等(即消費(fèi)端去重),RocketMQ為了保證性能并不支持嚴(yán)格的消息去重。
- 盡量使用批量方式消費(fèi),RocketMQ消費(fèi)端采用pull方式拉取消息,通過(guò)
consumeMessageBatchMaxSize參數(shù)可以增加單次拉取的消息數(shù)量,可以很大程度上提高消費(fèi)吞吐量。另外,提高消費(fèi)并行度也可以通過(guò)增加Consumer處理線(xiàn)程的方式,對(duì)應(yīng)參數(shù)consumeThreadMin和consumeThreadMax。 - 消息發(fā)送成功或者失敗,要打印消息日志。
補(bǔ)充
- 線(xiàn)上建議關(guān)閉
autoCreateTopicEnable配置
該配置用于在Topic不存在時(shí)自動(dòng)創(chuàng)建,會(huì)造成的問(wèn)題是自動(dòng)新建的Topic只會(huì)存在于一臺(tái)broker上,后續(xù)所有對(duì)該Topic的請(qǐng)求都會(huì)局限在單臺(tái)broker上,造成單點(diǎn)壓力。
- broker master宕機(jī)情況是否會(huì)丟消息
broker master宕機(jī),雖然理論上來(lái)說(shuō)不能向該broker寫(xiě)入但slave仍然能支持消費(fèi),但受限于rocketmq的網(wǎng)絡(luò)連接機(jī)制,默認(rèn)情況下最多需要30秒,消費(fèi)者才會(huì)發(fā)現(xiàn)該情況,這個(gè)時(shí)間可通過(guò)修改參數(shù)pollNameServerInteval來(lái)縮短。這個(gè)時(shí)間段內(nèi),發(fā)往該broker的請(qǐng)求都是失敗的,而且該broker的消息無(wú)法消費(fèi),因?yàn)榇藭r(shí)消費(fèi)者不知道該broker已經(jīng)掛掉。 直到消費(fèi)者得到master宕機(jī)通知后,才會(huì)轉(zhuǎn)向slave進(jìn)行消費(fèi),但是slave不能保證master的消息100%都同步過(guò)來(lái)了,因此會(huì)有少量的消息丟失。但是消息最終不會(huì)丟,一旦master恢復(fù),未同步過(guò)去的消息仍然會(huì)被消費(fèi)掉。