匠心零度 轉載請註明原創出處,謝謝!
RocketMQ網路部署圖
- NameServer:在系統中是做命名服務,更新和發現 broker服務。
- Broker-Master:broker 訊息主機伺服器。
- Broker-Slave: broker 訊息從機伺服器。
- Producer: 訊息生產者。
- Consumer: 訊息消費者。
說明: rocketmq系列都將會以rocketmq-4.1.0-incubating進行介紹。
在閱讀原始碼時做了一定的註釋,公眾號【匠心零度】回覆:rocketmq,可獲得基於rocketmq4.1.0加詳細中文程式碼註釋 。歡迎大家 star、fork !
廝大說過訊息中介軟體的本質訊息中介軟體大道至簡:一發一存一消費 ,今天主要來討論下發,就是RocketMQ網路部署圖中用顏色標記的部分。
往期rocketmq系列文章
- RocketMQ部分資料消費不了問題排查
- 讓你rocketmq用得比預期要好的 1 種方法
- RocketMQ(一):原始碼除錯
- rocketmq番外篇(一):開發命令列
- RocketMQ(六):namesrv再探
- RocketMQ(五):namesrv初探
- CRC 校驗
- RocketMQ(二):RPC通訊
- RocketMQ解惑篇
- RocketMQ快速入門
- MQ 應用場景
- RocketMQ叢集部署配置
- 阿里RocketMQ
訊息傳送概述
上面的圖大概就是producer傳送message到broker的核心邏輯了。
問題思考:
把broker相關資訊快取到客戶端減少了與namesrv的互動,但是也降低了broker變化的實時性了,如何忽然有一臺broker不可用了會怎麼樣呢?(後續看看rocketmq的處理),為什麼producer傳送會那麼快呢?本質是由於netty的writeAndFlush?producer如何做到非同步傳送?同步傳送?oneway傳送的呢?如果傳送失敗會怎麼處理呢?
訊息傳送一般流程分析
由於傳送還涉及到定時傳送,順序傳送,批量傳送等情況,本篇考慮到篇幅問題就是一般的傳送邏輯講解,後面繼續分享其他情況。
閱讀本篇前應該重點閱讀下:RocketMQ(二):RPC通訊。
如何在本地除錯之前文章也分享過了,在此就不提了,傳送的邏輯相對於儲存以及消費來說是最簡單的(直接根據一條線不斷的跟下去基本就差不多了),而儲存最複雜,其次消費(這些過程可能一條線不好找,後續分享)。
同步傳送寫法
備註: 可以參考RocketMQ快速入門即可。
producer.start
/**
* Start this producer instance.
* </p>
*
* <strong>
* Much internal initializing procedures are carried out to make this instance prepared, thus, it's a must to invoke
* this method before sending or querying messages.
* </strong>
* </p>
*
* @throws MQClientException if there is any unexpected error.
*/
@Override
public void start() throws MQClientException {
this.defaultMQProducerImpl.start();
}
複製程式碼
主要做了下列事情(核心事情):
- 一些配置檢查。
- 構建與namesrv通訊的netty客戶端。
- 預設每30s與namesrv交換獲取broker相關資訊。
- 預設每30s去掉失效的broker資訊以及傳送心跳到所有broker上面。
構建Message物件
producer是以Message物件進行傳送的,看看Message構造:
public Message() {
}
public Message(String topic, byte[] body) {
this(topic, "", "", 0, body, true);
}
public Message(String topic, String tags, String keys, int flag, byte[] body, boolean waitStoreMsgOK) {
this.topic = topic;
this.flag = flag;
this.body = body;
if (tags != null && tags.length() > 0)
this.setTags(tags);
if (keys != null && keys.length() > 0)
this.setKeys(keys);
this.setWaitStoreMsgOK(waitStoreMsgOK);
}
public Message(String topic, String tags, byte[] body) {
this(topic, tags, "", 0, body, true);
}
public Message(String topic, String tags, String keys, byte[] body) {
this(topic, tags, keys, 0, body, true);
}
複製程式碼
備註: 主要就是topic、tags、以及body真實內容等。
send傳送
SendResult sendResult = producer.send(msg);
複製程式碼
進行傳送處理。下面我們重點看看send如何處理。
傳送send核心分析
傳送的幾種方式:同步 非同步 oneway(應該選擇哪種,需要自己根據情況進行判斷)
以同步傳送為例子,預設超時時間為3s,
SendResult sendResult = producer.send(msg);
複製程式碼
這個就是傳送的觸發方法,我們一直跟進去就行了,**第一初步感受:**通過跟蹤進去第一感覺就是涉及到了JUC相關使用,大量運用享元模式(本質一個map進行快取)以及netty使用。
核心邏輯:
程式碼就不大量複製了,需要的github裡面獲取基於rocketmq4.1.0加詳細中文程式碼註釋 。歡迎大家 star、fork !
-
判斷服務是否可用? 不可用直接結束流程。
-
訊息的驗證:
-
獲取topic路由資訊
快取中有就獲取,沒有就namesrv互動一次(也可能2次)由於topic資訊在broker服務端不一定存在,如果不存在就用預設的(TBW102)。
封裝請求頭資訊:
// Namesrv 根據Topic獲取Broker Name、佇列數(包含讀佇列與寫佇列)
public static final int GET_ROUTEINTO_BY_TOPIC = 105;
複製程式碼
namesrv服務端接受到這個請求的處理情況。
最後得到的路由資訊類似下面的:
-
傳送模式是sync 會有3次其他1次
//傳送模式是sync 會有3次其他1次 int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1; 複製程式碼
-
選擇一個queue
如何選擇傳送那個broker的那個queueid上面?(客戶端自己負載),由於broker相關資訊快取在客戶端裡面,問題來了(由於30s會同步一次資訊,那麼在30s之內broker出現問題會怎麼樣呢? )rocketmq是這樣處理的:sendLatencyFaultEnable開關是否開啟
1.開啟--> 有多長時間內不可用情況
2.不開啟(預設)-->直接隨機一個(如果帶了lastBrokerName不為空 儘量換不是這個broker的,如果都沒有又是隨機一個)
-
呼叫sendKernelImpl傳送訊息 傳送訊息核心
根據broker的name獲取到ip地址,如果通道沒有建立並且儲存。
設定設定UNIQ_id,裡面保護客戶端ip地址資訊。
傳送的時候 會有鉤子函式提供執行(禁止訊息鉤子 ,傳送訊息鉤子(executeSendMessageHookBefore、executeSendMessageHookAfter)。
構建SendMessageRequestHeader,包括生成訊息時間戳,所以各各機器時間最好一致,(這樣後期也可以查下broker接受訊息花了多少時間)。
-
根據傳送訊息模式,選擇傳送方式
下面這次主要看同步傳送情況。
如果1情況執行nettywriteAndFlush傳送成功者跳出來,到達3情況進行等等最多等待3s。這裡什麼時候喚醒呢? 其實是在broker情況響應客戶端的時候進行喚醒的:
備註: 這裡使用CountDownLatch非同步轉同步的。
如果是2情況表示傳送失敗,直接喚醒3情況不進行阻塞了(最後拋異常表示傳送失敗)
-
更新broker可用時間
-
retryAnotherBrokerWhenNotStoreOK情況判斷
如果設定為retryAnotherBrokerWhenNotStoreOK為true之後,在傳送失敗的時候,會選擇換一個broker。
-
如下異常continue,進行傳送訊息重試
客戶端傳送流程大概到這裡就分析完成了。
如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【匠心零度】,查閱更多精彩歷史!!!
加入知識星球,一起探討!