RocketMQ實(shí)戰(zhàn)(二)

在上一篇《RocketMQ實(shí)戰(zhàn)(一)》中已經(jīng)為大家初步介紹了下RocketMQ以及搭建了雙Master環(huán)境,接下來繼續(xù)為大家介紹!

Quick Start

寫一個(gè)簡(jiǎn)單的生產(chǎn)者、消費(fèi)者,帶大家快速體驗(yàn)RocketMQ~

Maven配置:

pom.xml

生產(chǎn)者:

生產(chǎn)者代碼

消費(fèi)者:

消費(fèi)者代碼

無論生產(chǎn)者、消費(fèi)者都必須給出GroupName,而且具有唯一性!

生產(chǎn)到哪個(gè)Topic的哪個(gè)Tag下,消費(fèi)者也是從Topic的哪個(gè)Tag進(jìn)行消費(fèi),可見這個(gè)Tag有點(diǎn)類似于JMS Selector機(jī)制,即實(shí)現(xiàn)消息的過濾。

生產(chǎn)者、消費(fèi)者需要設(shè)置NameServer地址。

這里,采用的是Consumer Push的方式,即設(shè)置Listener機(jī)制回調(diào),相當(dāng)于開啟了一個(gè)線程。以后為大家介紹Consumer Pull的方式。

我們看一下運(yùn)行結(jié)果:

生產(chǎn)者運(yùn)行結(jié)果

仔細(xì)看看生產(chǎn)者結(jié)果輸出,你會(huì)發(fā)現(xiàn),有的消息發(fā)往broker-a,有的在broker-b上,自動(dòng)實(shí)現(xiàn)了消息的負(fù)載均衡!


消費(fèi)者運(yùn)行結(jié)果

這里消費(fèi)消息是沒有什么順序的,以后我們?cè)趤碚勏⒌捻樞蛐浴?/b>

我們?cè)賮砜匆豢垂芸嘏_(tái):

消息分布在2個(gè)broker上


消費(fèi)后

在多Master模式中,如果某個(gè)Master進(jìn)程掛了,顯然這臺(tái)broker將不可用,上面的消息也將無法消費(fèi),要知道開源版本的RocketMQ是沒有提供切換程序,來自動(dòng)恢復(fù)故障的,因此在實(shí)際開發(fā)中,我們一般提供一個(gè)監(jiān)聽程序,用于監(jiān)控Master的狀態(tài)。

在ActiveMQ中,生產(chǎn)消息的時(shí)候會(huì)提供是否持久化的選擇,但是對(duì)于RocketMQ而言,消息是一定會(huì)被持久化的!

上面的消費(fèi)者采用的是Push Consumer的方式,那么監(jiān)聽的Listener中的消息List到底是多少條呢?雖然提供了API,如consumer.setConsumeMessageBatchMaxSize(10),實(shí)際上即使設(shè)置了批量的條數(shù),但是注意了,是最大是10,并不意味著每次batch的都是10,只有在消息有擠壓的情況下才有可能。而且Push Consumer的最佳實(shí)踐方式就是一條條的消費(fèi),如果需要batch,可以使用Pull Consumer。

務(wù)必保證先啟動(dòng)消費(fèi)者進(jìn)行Topic訂閱,然后在啟動(dòng)生產(chǎn)者進(jìn)行生產(chǎn)(否則極有可能導(dǎo)致消息的重復(fù)消費(fèi),重復(fù)消費(fèi),重復(fù)消費(fèi)!重要的事情說三遍!關(guān)于消息的重復(fù)問題后續(xù)給大家介紹~)。而且在實(shí)際開發(fā)中,有時(shí)候不會(huì)批量的處理消息,而是原子性的,單線程的去一條一條的處理消息,這樣就是實(shí)時(shí)的在處理消息。(批量的處理海量的消息,可以考慮Kafka)


初步了解消息失敗重試機(jī)制

消息失敗,無非涉及到2端:從生產(chǎn)者端發(fā)往MQ的失敗;消費(fèi)者端從MQ消費(fèi)消息的失敗;

生產(chǎn)者端的失敗重試

生產(chǎn)者端失敗重試

生產(chǎn)者端的消息失敗:比如網(wǎng)絡(luò)抖動(dòng)導(dǎo)致生產(chǎn)者發(fā)送消息到MQ失敗。

上圖代碼示例的處理手段是:如果該條消息在1S內(nèi)沒有發(fā)送成功,那么重試3次。

消費(fèi)者端的失敗重試

消費(fèi)者端的失敗,分為2種情況,一個(gè)是timeout,一個(gè)是exception

timeout,比如由于網(wǎng)絡(luò)原因?qū)е孪焊蜎]有從MQ到消費(fèi)者上,在RocketMQ內(nèi)部會(huì)不斷的嘗試發(fā)送這條消息,直至發(fā)送成功為止!(比如集群中一個(gè)broker失敗,就嘗試另一個(gè)broker)

exception,消息正常的到了消費(fèi)者,結(jié)果消費(fèi)者發(fā)生異常,處理失敗了。這里涉及到一些問題,需要我們思考下,比如,消費(fèi)者消費(fèi)消息的狀態(tài)有哪些定義?如果失敗,MQ將采取什么策略進(jìn)行重試?假設(shè)一次性批量PUSH了10條,其中某條數(shù)據(jù)消費(fèi)異常,那么消息重試是10條呢,還是1條呢?而且在重試的過程中,需要保證不重復(fù)消費(fèi)嗎?


ConsumeConcurrentlyStatus

消息消費(fèi)的狀態(tài),有2種,一個(gè)是成功(CONSUME_SUCCESS),一個(gè)是失敗&稍后重試(RECONSUME_LATER)


broker啟動(dòng)日志

在啟動(dòng)broker的過程中,可以觀察下日志,你會(huì)發(fā)現(xiàn)RECONSUME_LATER的策略。

如果消費(fèi)失敗,那么1S后再次消費(fèi),如果失敗,那么5S后,再次消費(fèi),......直至2H后如果消費(fèi)還失敗,那么該條消息就會(huì)終止發(fā)送給消費(fèi)者了!

RocketMQ為我們提供了這么多次數(shù)的失敗重試,但是在實(shí)際中也許我們并不需要這么多重試,比如重試3次,還沒有成功,我們希望把這條消息存儲(chǔ)起來并采用另一種方式處理,而且希望RocketMQ不要在重試呢,因?yàn)橹卦嚱鉀Q不了問題了!這該如何做呢?

我們先來看一下一條消息MessageExt對(duì)象的輸出:

MessageExt [queueId=0, storeSize=137, queueOffset=0, sysFlag=0, bornTimestamp=1492213846916, bornHost=/192.168.99.219:50478, storeTimestamp=1492213846981, storeHost=/192.168.99.121:10911, msgId=C0A8637900002A9F0000000000000000, commitLogOffset=0, bodyCRC=613185359, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message [topic=TopicTest2, flag=0, properties={TAGS=TagA, WAIT=true, MAX_OFFSET=3, MIN_OFFSET=0}, body=16]]

注意到reconsumeTimes屬性,這個(gè)屬性就代表消息重試的次數(shù)!來看一段代碼:

reconsumeTime的使用

注意了,對(duì)于消費(fèi)消息而言,存在2種指定的狀態(tài)(成功 OR 失敗重試),如果一條消息在消費(fèi)端處理沒有返回這2個(gè)狀態(tài),那么相當(dāng)于這條消息沒有達(dá)到消費(fèi)者,勢(shì)必會(huì)再次發(fā)送給消費(fèi)者!也即是消息的處理必須有返回值,否則就進(jìn)行重發(fā)。


天然的消息負(fù)載均衡及高效的水平擴(kuò)展機(jī)制


消息的負(fù)載均衡

對(duì)于RocketMQ而言,通過ConsumeGroup的機(jī)制,實(shí)現(xiàn)了天然的消息負(fù)載均衡!通俗點(diǎn)來說,RocketMQ中的消息通過ConsumeGroup實(shí)現(xiàn)了將消息分發(fā)到C1/C2/C3/......的機(jī)制,這意味著我們將非常方便的通過加機(jī)器來實(shí)現(xiàn)水平擴(kuò)展!

我們考慮一下這種情況:比如C2發(fā)生了重啟,一條消息發(fā)往C3進(jìn)行消費(fèi),但是這條消息的處理需要0.1S,而此時(shí)C2剛好完成重啟,那么C2是否可能會(huì)收到這條消息呢?答案是肯定的,也就是consume broker的重啟,或者水平擴(kuò)容,或者不遵守先訂閱后生產(chǎn)消息,都可能導(dǎo)致消息的重復(fù)消費(fèi)!關(guān)于去重的話題會(huì)在后續(xù)中予以介紹!

至于消息分發(fā)到C1/C2/C3,其實(shí)也是可以設(shè)置策略的。


消息負(fù)載策略


集群消費(fèi) AND 廣播消費(fèi)

RocketMQ的消費(fèi)方式有2種,在默認(rèn)情況下,就是集群消費(fèi),也就是上面提及的消息的負(fù)載均衡消費(fèi)。另一種消費(fèi)模式,是廣播消費(fèi)。廣播消費(fèi),類似于ActiveMQ中的發(fā)布訂閱模式,消息會(huì)發(fā)給Consume Group中的每一個(gè)消費(fèi)者進(jìn)行消費(fèi)。


消費(fèi)模式


設(shè)置消費(fèi)模式


OK,到這里,本期的RocketMQ就結(jié)束了,咱們下期見~

周末愉快!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 分布式開放消息系統(tǒng)(RocketMQ)的原理與實(shí)踐 來源:http://www.lxweimin.com/p/453...
    meng_philip123閱讀 13,067評(píng)論 6 104
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,948評(píng)論 18 139
  • 背景介紹 Kafka簡(jiǎn)介 Kafka是一種分布式的,基于發(fā)布/訂閱的消息系統(tǒng)。主要設(shè)計(jì)目標(biāo)如下: 以時(shí)間復(fù)雜度為O...
    高廣超閱讀 12,884評(píng)論 8 167
  • 消息中間件需要解決哪些問題? Publish/Subscribe 發(fā)布訂閱是消息中間件的最基本功能,也是相對(duì)于傳統(tǒng)...
    壹點(diǎn)零閱讀 1,633評(píng)論 0 7
  • 我發(fā)現(xiàn)咨詢是一件和生活很相似的事情,當(dāng)來訪者不想透露太多時(shí)你不要去挖掘,當(dāng)你挖掘的越多你和來訪者可能都會(huì)受到傷害,...
    coolsharer閱讀 240評(píng)論 0 0