RocketMQ初步应用架构理论
RocketMQ初步應(yīng)用架構(gòu)理論
寫(xiě)給RocketMQ架構(gòu)應(yīng)用入門,內(nèi)容涉及它的設(shè)計(jì)機(jī)理以及推到出來(lái)的應(yīng)用注意事項(xiàng),入門人員請(qǐng)看。稍微涉及技術(shù)細(xì)節(jié),留以我設(shè)計(jì)中間件時(shí)參考,將來(lái)整理深度文檔時(shí)會(huì)抽取走,入門人員可以無(wú)視。
以下RocketMQ簡(jiǎn)稱為RQ,理論部分采用版本為3.2.4,測(cè)試部分采用版本為3.2.6。
MQ的需求
我們對(duì)MQ的需求,相比JMS標(biāo)準(zhǔn)有幾點(diǎn)要求更高:
1. 必須優(yōu)美靈活地支持集群消費(fèi)。
2. 盡量支持消息堆積。
3. 服務(wù)高可用性和消息可靠性。
4. 有起碼的運(yùn)維工具做集群管理和服務(wù)調(diào)整。
其他 提供順序消息、事務(wù)、回溯等面向特別場(chǎng)景的功能更好,目前暫不需要。
?
RQ架構(gòu)
RQ的基本組成包括nameserver、broker、producer、consumer四種節(jié)點(diǎn),前兩種構(gòu)成服務(wù)端,后兩種在客戶端上。
還有其他輔助的進(jìn)程,不提。
NameServer的基本概念
在沒(méi)有NameServer的中間件中,服務(wù)端集群就由干活的broker組成 ,其中的實(shí)例分主從兩種角色。那么客戶端就要知道,需要連接到哪個(gè)地址的broker上去做事情,于是客戶端就需要配置服務(wù)端機(jī)器的IP地址,如果服務(wù)端部署結(jié)構(gòu)復(fù)雜,客戶端的配置結(jié)構(gòu)也挺復(fù)雜,更討厭的是甚至可能需要客戶端也得更新地址配置。由于有了兩種思路的方案:
一是引入NameServer,負(fù)責(zé)提供地址。客戶端只需要知道NameServer機(jī)器的地址,需要找服務(wù)器干活的時(shí)候,先問(wèn)NameServer我該去找哪個(gè)服務(wù)器。這樣,因?yàn)镹ameServer很簡(jiǎn)單而不容易出故障,所以極少發(fā)生架構(gòu)調(diào)整。而結(jié)構(gòu)復(fù)雜的broker部分,無(wú)論怎么調(diào)整,客戶端都不用再操心。
RQ 2.x用的是Zookeeper做NameServer,3.x用的是自己搞的獨(dú)立服務(wù),不知道為啥,不過(guò)代碼貌似不復(fù)雜。
二是引入反向代理,就是把服務(wù)端地址配置成虛擬IP或域名這種思路,這一個(gè)地址背后其實(shí)可能是一個(gè)集群,客戶端發(fā)起請(qǐng)求后,由網(wǎng)絡(luò)設(shè)施來(lái)中轉(zhuǎn)請(qǐng)求給具體服務(wù)器。
兩者各有優(yōu)劣,綜合使用也挺正常。
NameServer的工作機(jī)制
I.NameServer自身之間的機(jī)制
可以啟動(dòng)多個(gè)實(shí)例,相互獨(dú)立,不需要相互通信,可以理解為多機(jī)熱備。
II.NameServer與broker之間
Broker啟動(dòng)后,向指定的一批NameServer發(fā)起長(zhǎng)連接,此后每隔30s發(fā)送一次心跳,心跳內(nèi)容中包含了所承載的topic信息;NameServer會(huì)每隔2分鐘掃描,如果2分鐘內(nèi)無(wú)心跳,就主動(dòng)斷開(kāi)連接。
當(dāng)然如果Broker掛掉,連接肯定也會(huì)斷開(kāi)。
一旦連接斷開(kāi),因?yàn)槭情L(zhǎng)連接,所以NameServer立刻就會(huì)感知有broker掛掉了,于是更新topic與broker的關(guān)系。但是,并不會(huì)主動(dòng)通知客戶端。
III.NameServer與客戶端之間
客戶端啟動(dòng)時(shí),要指定這些NameServer的具體地址。之后隨機(jī)與其中一臺(tái)NameServer保持長(zhǎng)連接,如果該NameServer發(fā)生了不可用,那么會(huì)連接下一個(gè)。
連接后會(huì)定時(shí)查詢topic路由信息,默認(rèn)間隔是30s,可配置,可編碼指定pollNameServerInteval。
(注意是定時(shí)的機(jī)制,不是即時(shí)查詢,也不是NameServer感知變更后推送,所以這里造成接收消息的實(shí)時(shí)性問(wèn)題)。
?
NameServer的部署與應(yīng)用
I. 運(yùn)行NameServer
啟動(dòng): nohup mqnamesrv &
終止:
sh ./mqshutdown Useage: mqshutdown broker | namesrvII. Broker指定NameServer
有幾種方式 1.啟動(dòng)命令指定 nohup mqbroker -n?"192.168.36.53:9876;192.168.36.80:9876"?& 2.環(huán)境變量指定 export NAMESRV_ADDR=192.168.36.53:9876;192.168.36.80:9876 3.配置指定?
bin和conf下面的配置文件里面有| root@rocketmq-master1 bin]# sh mqbroker -m namesrvAddr= |
?
III.客戶端指定NameServer
有幾種方式:
1.編碼指定
producer.setNamesrvAddr("192.168.36.53:9876;192.168.36.80:9876");
所以這里指定的并不是broker的主主或主從機(jī)器的地址,而是NameServer的地址。
2.java啟動(dòng)參數(shù)
-Drocketmq.namesrv.addr=192.168.36.53:9876;192.168.36.80:9876 3.環(huán)境變量 export NAMESRV_ADDR=192.168.36.53:9876;192.168.36.80:9876 4.服務(wù)客戶端還可以配置這個(gè)域名jmenv.tbsite.alipay.net來(lái)尋址,就不用指定IP了,這樣NameServer集群可以做熱升級(jí)。
該接口具體地址是http://jmenv.tbsite.net:8080/rocketmq/nsaddr
(理論上,最后一種可用性最好;實(shí)際上,沒(méi)試出來(lái)。)?
Broker的機(jī)制
I.消息的存儲(chǔ)
1.topic與broker是多對(duì)多的關(guān)系,一個(gè)topic可以做分區(qū)配置的,使得可以分散為隊(duì)列交付給多個(gè)btoker。分區(qū)的設(shè)計(jì)采用的是偏移量做法。 2.Broker是把消息持久化到磁盤文件的,同步刷盤就是寫(xiě)入后才告知producer成功;異步刷盤是收到消息后就告知producer成功了,之后異步地將消息從內(nèi)存(PageCache)寫(xiě)入到磁盤上。 (注意此處涉及到磁盤寫(xiě)入速度是否大于網(wǎng)卡速度的問(wèn)題,應(yīng)用的不好可能造成消息堆積) 3.磁盤空間達(dá)到85%之后,不再接收消息,會(huì)打印日志并且告知producer發(fā)送消息失敗。 4.持久化采取的是ext4文件系統(tǒng),存儲(chǔ)的數(shù)據(jù)結(jié)構(gòu)另有其他文檔,運(yùn)維時(shí)需要處理文件目錄時(shí)另說(shuō)。II.消息的清理
1.每隔10s掃描消息,可以通過(guò)cleanResourceInterval配置。 2.每天4點(diǎn)清理消息,可以通過(guò)deleteWhen配置。磁盤空間達(dá)到閾值時(shí)也會(huì)啟動(dòng)。 3.文件保留時(shí)長(zhǎng)為72小時(shí),可以通過(guò)fileReservedTime配置。也就是消息堆積的時(shí)限。III.消息的消費(fèi)
1.IO用的是文件內(nèi)存映射方式,性能較高,只會(huì)有一個(gè)寫(xiě),其他的讀。順序?qū)?#xff0c;隨機(jī)讀。
2. 零拷貝原理:
以前使用linux 的sendfile 機(jī)制,利用DMA(優(yōu)點(diǎn)是CPU不參與傳輸),將消息內(nèi)容直接輸出到sokect 管道,大塊文件傳輸效率高。缺點(diǎn)是只能用BIO。
于是此版本使用的是mmap+write方式,代價(jià)是CPU多耗用一些,內(nèi)存安全問(wèn)題復(fù)雜一些,要避免JVM Crash。
IV.Topic管理
1.客戶端可以配置是否允許自動(dòng)創(chuàng)建Topic,不允許的話,要先在console上增加此Topic。同時(shí)提供管理操作。V.物理特性
1.CPU:Load高,但使用率低,因?yàn)榇蟛糠謺r(shí)間在IO Wait。
2. 內(nèi)存:依舊需要大內(nèi)存,否則swap會(huì)成為瓶頸。
3. 磁盤:IO密集,轉(zhuǎn)速越高、可靠性越高越好。
VI.broker之間的機(jī)制
單機(jī)的刷盤機(jī)制,雖然保障消息可靠性,但是存在單點(diǎn)故障影響服務(wù)可用性,于是有了HA的一些方式。
1.主從雙寫(xiě)模式,在消息可靠性上依然很高,但是有小問(wèn)題。
a.master宕機(jī)之后,客戶端會(huì)得到slave的地址繼續(xù)消費(fèi),但是不能發(fā)布消息。
b.客戶端在與NameServer直接網(wǎng)絡(luò)機(jī)制的延遲下,會(huì)發(fā)生一部分消息延遲,甚至要等到master恢復(fù)。
c.發(fā)現(xiàn)slave有消息堆積后,會(huì)令consumer從slave先取數(shù)據(jù)。
?2 異步復(fù)制,消息可靠性上肯定小于主從雙寫(xiě)
slave的線程不斷從master拉取commitLog的數(shù)據(jù),然后異步構(gòu)建出數(shù)據(jù)結(jié)構(gòu)。類似mysql的機(jī)制。
VII.與consumer之間的機(jī)制
1.服務(wù)端隊(duì)列
topic的一個(gè)隊(duì)列只會(huì)被一個(gè)consumer消費(fèi),所以該consumer節(jié)點(diǎn)最好屬于一個(gè)集群。
那么也意味著,comsumer節(jié)點(diǎn)的數(shù)量>topic隊(duì)列的數(shù)量,多出來(lái)的那些comsumer會(huì)閑著沒(méi)事干。
舉簡(jiǎn)單例子說(shuō)明:
假設(shè)broker有2臺(tái)機(jī)器,topic設(shè)置了4個(gè)隊(duì)列,那么一個(gè)broker機(jī)器上就承擔(dān)2個(gè)隊(duì)列。
此時(shí)消費(fèi)者所屬的系統(tǒng),有8臺(tái)機(jī)器,那么運(yùn)行之后,其中就只有4臺(tái)機(jī)器連接到了MQ服務(wù)端的2臺(tái)broker上,剩下的4臺(tái)機(jī)器是不消費(fèi)消息的。
所以,此時(shí)要想負(fù)載均衡,要把topic的分區(qū)數(shù)量設(shè)高。
2.可靠性
consumer與所有關(guān)聯(lián)的broker保持長(zhǎng)連接(包括主從),每隔30s發(fā)送心跳,可配置,可以通過(guò)heartbeatBrokerInterval配置。
broker每隔10s掃描連接,發(fā)現(xiàn)2分鐘內(nèi)沒(méi)有心跳,則關(guān)閉連接,并通知該consumer組內(nèi)其他實(shí)例,過(guò)來(lái)繼續(xù)消費(fèi)該topic。
當(dāng)然,因?yàn)槭情L(zhǎng)連接,所以consumer掛掉也會(huì)即時(shí)發(fā)生上述動(dòng)作。所以,consumer集群的情況下,消費(fèi)是可靠的。
而因?yàn)閏onsumer與所有broker都持有連接,所以可以兩種角色都訂閱消息,規(guī)則由broker來(lái)自動(dòng)決定(比如master掛了之后重啟,要先消費(fèi)哪一臺(tái)上的消息)。
3.本地隊(duì)列
consumer有線程不斷地從broker拉取消息到本地隊(duì)列中,消費(fèi)線程異步消費(fèi)。輪詢間隔可指定pullInterval參數(shù),默認(rèn)0;本地隊(duì)列大小可指定pullThresholdForQueue,默認(rèn)1000。
而不論consumer消費(fèi)多少個(gè)隊(duì)列,與一個(gè)broker只有一個(gè)連接,會(huì)有一個(gè)任務(wù)隊(duì)列來(lái)維護(hù)拉取隊(duì)列消息的任務(wù)。
4.消費(fèi)進(jìn)度上報(bào)
定時(shí)上報(bào)各個(gè)隊(duì)列的消費(fèi)情況到broker上,時(shí)間間隔可設(shè)persistConsumerOffsetInterval。
上述采取的是DefaultMQPushConsumer類做的描述,可見(jiàn)所謂push模式還是定時(shí)拉取的,不是所猜測(cè)的服務(wù)端主動(dòng)推送。不過(guò)拉取采用的是長(zhǎng)輪詢的方式,實(shí)時(shí)性基本等同推送。
?VIII.與producer的機(jī)制
1.可靠性
a.producer與broker的網(wǎng)絡(luò)機(jī)制,與consumer的相同。如果producer掛掉,broker會(huì)移除producer的信息,直到它重新連接。
b.producer發(fā)送消息失敗,最多可以重試3次,或者不超過(guò)10s的超時(shí)時(shí)間,此時(shí)間可通過(guò)sendMsgTimeout配置。如果發(fā)送失敗,輪轉(zhuǎn)到下一個(gè)broker。
c.producer也可以采用oneway的方式,只負(fù)責(zé)把數(shù)據(jù)寫(xiě)入客戶端機(jī)器socket緩沖區(qū)。這樣可靠性較低,但是開(kāi)銷大大減少。(適合采集小數(shù)據(jù)日志)
2.消息負(fù)載
發(fā)送消息給broker集群時(shí),是輪流發(fā)送的,來(lái)保障隊(duì)列消息量平均。也可以自定義往哪一個(gè)隊(duì)列發(fā)送。
3.停用機(jī)制
當(dāng)broker重啟的時(shí)候,可能導(dǎo)致此時(shí)消息發(fā)送失敗。于是有命令可以先停止寫(xiě)權(quán)限,40s后producer便不會(huì)再把消息往這臺(tái)broker上發(fā)送,從而可以重啟。
sh?mqadmin?wipeWritePerm?-b?brokerName?-n?namesrvAddr
IX.通信機(jī)制
1.組件采用的是Netty.4.0.9。
2.協(xié)議是他們自己定的新玩意,并不兼容JMS標(biāo)準(zhǔn)。協(xié)議具體內(nèi)容有待我開(kāi)發(fā)C#版客戶端時(shí)看詳情。
3.連接是可以復(fù)用的,通過(guò)header的opaque標(biāo)示區(qū)分。
Broker的集群部署
一句話總結(jié)其特征就是:不支持主從自動(dòng)切換、slave只能讀不能寫(xiě),所以故障后必須人工干預(yù)恢復(fù)負(fù)載。
| 一組主主 | 結(jié)構(gòu)簡(jiǎn)單,擴(kuò)容方便,機(jī)器要求低 | 同步刷盤消息一條都不會(huì)丟 | 整體可用 未被消費(fèi)的消息無(wú)法取得,影響實(shí)時(shí)性 | 性能最高 | 適合消息可靠性最高、實(shí)時(shí)性低的需求。 |
| 一組主從 | ? | 異步有毫秒級(jí)丟失; 同步雙寫(xiě)不丟失; | 差評(píng),主備不能自動(dòng)切換,且備機(jī)只能讀不能寫(xiě),會(huì)造成服務(wù)整體不可寫(xiě)。 | ? | 不考慮,除非自己提供主從切換的方案。 |
| 多組主從(異步復(fù)制) | 結(jié)構(gòu)復(fù)雜,擴(kuò)容方便 | 故障時(shí)會(huì)丟失消息; | 整體可用,實(shí)時(shí)性影響毫秒級(jí)別 該組服務(wù)只能讀不能寫(xiě) | 性能很高 | 適合消息可靠性中等,實(shí)時(shí)性中等的要求。 |
| 多組主從(同步雙寫(xiě)) | 結(jié)構(gòu)復(fù)雜,擴(kuò)容方便 | 不丟消息 | 整體可用,不影響實(shí)時(shí)性 該組服務(wù)只能讀不能寫(xiě)。 不能自動(dòng)切換? | 性能比異步低10%,所以實(shí)時(shí)性也并不比異步方式太高。 | 適合消息可靠性略高,實(shí)時(shí)性中等、性能要求不高的需求。 |
第四種的官方介紹上,比第三種多說(shuō)了一句:“不支持主從自動(dòng)切換”。這句話讓我很恐慌,因?yàn)榈谌N也是不支持的,干嘛第四種偏偏多說(shuō)這一句,難道可用性上比第三種差?
于是做了實(shí)驗(yàn),證明第三種和第四種可用性是一模一樣的。那么不支持主從切換是什么意思?推斷編寫(xiě)者是這個(gè)意圖:
因?yàn)槭侵鲝碾p寫(xiě)的,所以數(shù)據(jù)一致性非常高,那么master掛了之后,slave本是可以立刻切換為主的,這一點(diǎn)與異步復(fù)制不一樣。異步復(fù)制并沒(méi)有這么高的一致性,所以這一句話并不是提醒,而是一個(gè)后續(xù)功能的備注,可以在雙寫(xiě)的架構(gòu)上繼續(xù)發(fā)展出自動(dòng)主從切換的功能。
?
架構(gòu)測(cè)試總結(jié):
1.其實(shí)根本不用糾結(jié),高要求首選同步雙寫(xiě),低要求選主主方案。
2.最好不用一個(gè)機(jī)器上部署多個(gè)broker實(shí)例。端口容易沖突,根源問(wèn)題還沒(méi)掌握。
所以,建議采用多臺(tái)機(jī)器,一臺(tái)起一個(gè)broker,構(gòu)成同步雙寫(xiě)的架構(gòu)。也就是官方提供的這種物理和邏輯架構(gòu)。
注意幾個(gè)特征:
a.客戶端是先從NameServer尋址的,得到可用Broker的IP和端口信息,然后自己去連接broker。
b.生產(chǎn)者與所有的master連接,但不能向slave寫(xiě)入;而消費(fèi)者與master和slave都建有連接,在不同場(chǎng)景有不同的消費(fèi)規(guī)則。
c.NameServer不去連接別的機(jī)器,不主動(dòng)推消息。
?
客戶端的概念
1.Producer Group
Producer實(shí)例的集合。
Producer實(shí)例可以是多機(jī)器、但機(jī)器多進(jìn)程、單進(jìn)程中的多對(duì)象。Producer可以發(fā)送多個(gè)Topic。
處理分布式事務(wù)時(shí),也需要Producer集群提高可靠性。
2.Consumer Group
Consumer實(shí)例?的集合。
Consumer?實(shí)例可以是多機(jī)器、但機(jī)器多進(jìn)程、單進(jìn)程中的多對(duì)象。
同一個(gè)Group中的實(shí)例,在集群模式下,以均攤的方式消費(fèi);在廣播模式下,每個(gè)實(shí)例都全部消費(fèi)。
3.Push Consumer
應(yīng)用通常向Consumer對(duì)象注冊(cè)一個(gè)Listener接口,一旦收到消息,Consumer對(duì)象立刻回調(diào)Listener接口方法。所以,所謂Push指的是客戶端內(nèi)部的回調(diào)機(jī)制,并不是與服務(wù)端之間的機(jī)制。
4.Pull Consumer
應(yīng)用通常主動(dòng)調(diào)用Consumer從服務(wù)端拉消息,然后處理。這用的就是短輪詢方式了,在不同情況下,與長(zhǎng)輪詢各有優(yōu)點(diǎn)。
?
發(fā)布者和消費(fèi)者類庫(kù)另有文檔,不提。
?
重要問(wèn)題總結(jié):
1.客戶端選擇推還是拉,其實(shí)考慮的是長(zhǎng)輪詢和短輪詢的適用場(chǎng)景。
2.服務(wù)端首選同步雙寫(xiě)架構(gòu),但依然可能造成故障后30s的消息實(shí)時(shí)性問(wèn)題(客戶端機(jī)制決定的)。
3.Topic管理,需要先調(diào)查客戶端集群機(jī)器的數(shù)目,合理設(shè)置隊(duì)列數(shù)量之后,再上線。
轉(zhuǎn)載于:https://www.cnblogs.com/LifeOnCode/p/4805953.html
總結(jié)
以上是生活随笔為你收集整理的RocketMQ初步应用架构理论的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: php session_regenera
- 下一篇: 五子课堂---第一课(连珠基础一)