在上一篇《RocketMQ實戰(一)》中已經為大家初步介紹了下RocketMQ以及搭建了雙Master環境,接下來繼續為大家介紹!
Quick Start
寫一個簡單的生產者、消費者,帶大家快速體驗RocketMQ~
Maven配置:
生產者:
消費者:
無論生產者、消費者都必須給出GroupName,而且具有唯一性!
生產到哪個Topic的哪個Tag下,消費者也是從Topic的哪個Tag進行消費,可見這個Tag有點類似于JMS Selector機制,即實現消息的過濾。
生產者、消費者需要設置NameServer地址。
這里,采用的是Consumer Push的方式,即設置Listener機制回調,相當于開啟了一個線程。以后為大家介紹Consumer Pull的方式。
我們看一下運行結果:
仔細看看生產者結果輸出,你會發現,有的消息發往broker-a,有的在broker-b上,自動實現了消息的負載均衡!
這里消費消息是沒有什么順序的,以后我們在來談消息的順序性。
我們再來看一看管控臺:
在多Master模式中,如果某個Master進程掛了,顯然這臺broker將不可用,上面的消息也將無法消費,要知道開源版本的RocketMQ是沒有提供切換程序,來自動恢復故障的,因此在實際開發中,我們一般提供一個監聽程序,用于監控Master的狀態。
在ActiveMQ中,生產消息的時候會提供是否持久化的選擇,但是對于RocketMQ而言,消息是一定會被持久化的!
上面的消費者采用的是Push Consumer的方式,那么監聽的Listener中的消息List到底是多少條呢?雖然提供了API,如consumer.setConsumeMessageBatchMaxSize(10),實際上即使設置了批量的條數,但是注意了,是最大是10,并不意味著每次batch的都是10,只有在消息有擠壓的情況下才有可能。而且Push Consumer的最佳實踐方式就是一條條的消費,如果需要batch,可以使用Pull Consumer。
務必保證先啟動消費者進行Topic訂閱,然后在啟動生產者進行生產(否則極有可能導致消息的重復消費,重復消費,重復消費!重要的事情說三遍!關于消息的重復問題后續給大家介紹~)。而且在實際開發中,有時候不會批量的處理消息,而是原子性的,單線程的去一條一條的處理消息,這樣就是實時的在處理消息。(批量的處理海量的消息,可以考慮Kafka)
初步了解消息失敗重試機制
消息失敗,無非涉及到2端:從生產者端發往MQ的失??;消費者端從MQ消費消息的失?。?/b>
生產者端的失敗重試
生產者端的消息失?。罕热缇W絡抖動導致生產者發送消息到MQ失敗。
上圖代碼示例的處理手段是:如果該條消息在1S內沒有發送成功,那么重試3次。
消費者端的失敗重試
消費者端的失敗,分為2種情況,一個是timeout,一個是exception
timeout,比如由于網絡原因導致消息壓根就沒有從MQ到消費者上,在RocketMQ內部會不斷的嘗試發送這條消息,直至發送成功為止?。ū热缂褐幸粋€broker失敗,就嘗試另一個broker)
exception,消息正常的到了消費者,結果消費者發生異常,處理失敗了。這里涉及到一些問題,需要我們思考下,比如,消費者消費消息的狀態有哪些定義?如果失敗,MQ將采取什么策略進行重試?假設一次性批量PUSH了10條,其中某條數據消費異常,那么消息重試是10條呢,還是1條呢?而且在重試的過程中,需要保證不重復消費嗎?
消息消費的狀態,有2種,一個是成功(CONSUME_SUCCESS),一個是失敗&稍后重試(RECONSUME_LATER)
在啟動broker的過程中,可以觀察下日志,你會發現RECONSUME_LATER的策略。
如果消費失敗,那么1S后再次消費,如果失敗,那么5S后,再次消費,......直至2H后如果消費還失敗,那么該條消息就會終止發送給消費者了!
RocketMQ為我們提供了這么多次數的失敗重試,但是在實際中也許我們并不需要這么多重試,比如重試3次,還沒有成功,我們希望把這條消息存儲起來并采用另一種方式處理,而且希望RocketMQ不要在重試呢,因為重試解決不了問題了!這該如何做呢?
我們先來看一下一條消息MessageExt對象的輸出:
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屬性,這個屬性就代表消息重試的次數!來看一段代碼:
注意了,對于消費消息而言,存在2種指定的狀態(成功 OR 失敗重試),如果一條消息在消費端處理沒有返回這2個狀態,那么相當于這條消息沒有達到消費者,勢必會再次發送給消費者!也即是消息的處理必須有返回值,否則就進行重發。
天然的消息負載均衡及高效的水平擴展機制
對于RocketMQ而言,通過ConsumeGroup的機制,實現了天然的消息負載均衡!通俗點來說,RocketMQ中的消息通過ConsumeGroup實現了將消息分發到C1/C2/C3/......的機制,這意味著我們將非常方便的通過加機器來實現水平擴展!
我們考慮一下這種情況:比如C2發生了重啟,一條消息發往C3進行消費,但是這條消息的處理需要0.1S,而此時C2剛好完成重啟,那么C2是否可能會收到這條消息呢?答案是肯定的,也就是consume broker的重啟,或者水平擴容,或者不遵守先訂閱后生產消息,都可能導致消息的重復消費!關于去重的話題會在后續中予以介紹!
至于消息分發到C1/C2/C3,其實也是可以設置策略的。
集群消費 AND 廣播消費
RocketMQ的消費方式有2種,在默認情況下,就是集群消費,也就是上面提及的消息的負載均衡消費。另一種消費模式,是廣播消費。廣播消費,類似于ActiveMQ中的發布訂閱模式,消息會發給Consume Group中的每一個消費者進行消費。
OK,到這里,本期的RocketMQ就結束了,咱們下期見~
周末愉快!