DefaultMQProducerImpl
啓動
start方法
-
producerGroup如果不是CLIENT_INNER_PRODUCER,並且intanceName=DEFAULT,則把instanceName改爲PID
-
mQClientFactory是一個MQClientInstance對象,由MQClientManager管理,這是一個單例,其中ConcurrentMap<String/* clientId */, MQClientInstance> factoryTable 用來維護創建的MQClientInstance對象。
- 創建mQClientFactory時首先根據創建clientId=ip+instanceName+unitName,根據這個id在factoryTable中獲取對象
- 如果爲空,則創建一個新的對象,放入factoryTable中
-
註冊producer到mQClientFactory
- mQClientFactory中維護一個ConcurrentMap<String/* group */, MQProducerInner> producerTable對象緩存創建的producer
- 根據當前producer的producerGroup從map中獲取,沒有則直接將當前producer放入map中,如果producerGroup已存在則會提示producerGroup已存在
-
DefaultMQProducerImpl 維護一個ConcurrentMap<String/* topic */, TopicPublishInfo> topicPublishInfoTable,緩存topic和TopicPublishInfo,新建一個topicPublishInfoTable放入table中
-
調用mQClientFactory的start方法,啓動流程包括:
- 獲取nameServer地址,如果沒有則用http請求從配置url中獲取
this.mQClientAPIImpl.fetchNameServerAddr();
- 啓動mqClientAPIImpl
// Start request-response channel this.mQClientAPIImpl.start();
- 啓動各種定時任務
// Start various schedule tasks this.startScheduledTask();
定時任務包括:
* fetchNameServerAddr * updateTopicRouteInfoFromNameServer * cleanOfflineBroker&sendHeartbeatToAllBrokerWithLock * persistAllConsumerOffset * adjustThreadPool
- 啓動pull service線程
// Start pull service this.pullMessageService.start();
- 啓動負載均衡線程
// Start rebalance service this.rebalanceService.start();
- 啓動push service,這裏又是start方法,區別是startFactory
參數爲false
// Start push service this.defaultMQProducer.getDefaultMQProducerImpl().start(false);
start方法:
public void start(final boolean startFactory) throws MQClientException {
switch (this.serviceState) {
case *CREATE_JUST*:
this.serviceState = ServiceState.*START_FAILED*;
this.checkConfig();
if (!this.defaultMQProducer.getProducerGroup().equals(MixAll.*CLIENT_INNER_PRODUCER_GROUP*)) {
this.defaultMQProducer.changeInstanceNameToPID();
}
this.mQClientFactory = MQClientManager.*getInstance*().getAndCreateMQClientInstance(this.defaultMQProducer, rpcHook);
boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this);
if (!registerOK) {
this.serviceState = ServiceState.*CREATE_JUST*;
throw new MQClientException("The producer group[" + this.defaultMQProducer.getProducerGroup()
+ "] has been created before, specify another name please." + FAQUrl.*suggestTodo*(FAQUrl.*GROUP_NAME_DUPLICATE_URL*),
null);
}
this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo());
if (startFactory) {
mQClientFactory.start();
}
log.info("the producer [{}] start OK. sendMessageWithVIPChannel={}", this.defaultMQProducer.getProducerGroup(),
this.defaultMQProducer.isSendMessageWithVIPChannel());
this.serviceState = ServiceState.*RUNNING*;
break;
case *RUNNING*:
case *START_FAILED*:
case *SHUTDOWN_ALREADY*:
throw new MQClientException("The producer service state not OK, maybe started once, "
+ this.serviceState
+ FAQUrl.*suggestTodo*(FAQUrl.*CLIENT_SERVICE_NOT_OK*),
null);
default:
break;
}
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
}
發送消息
RockeMq支持三種消息發送方式
- 同步,producer向mq發送消息時同步等待,直到服務器返回發送結果或超時
- 異步,producer向mq發送消息時制定發送成功後的回調函數,消息發送成功或失敗會在另外的線程執行回調函數
- 單向,producer向mq發送消息時直接返回,不等待消息發送結果也不註冊回調函數
消息發送的基本流程包括
- 校驗消息
- 查找路由
- 消息發送(含異常處理機制)
驗證消息
校驗消息的主題,消息體不能爲空,長度大於0且小於4M(默認)
查找路由信息
-
在本地topicPublishInfoTable緩存中根據topic獲取
-
如果沒有或者狀態不ok,則updateTopicRouteInfoFromNameServer,從nameServer根據topic獲取並放入緩存,拿到TopicPublishInfo對象,轉爲topicRouteData對象
-
路由信息在TopicPublishInfo對象中
private boolean orderTopic = false; //是否是順序消息
private boolean haveTopicRouterInfo = false;
private List<MessageQueue> messageQueueList = new ArrayList<MessageQueue>(); //該主題的消息隊列
private volatile ThreadLocalIndex sendWhichQueue = new ThreadLocalIndex(); //每選擇一次消息隊列,會+1,用於次選擇消息隊列
private TopicRouteData topicRouteData;
topicRouteData對象
private String orderTopicConf;
private List<QueueData> queueDatas; //topic隊列元數據
private List<BrokerData> brokerDatas; //topic分佈的broker元數據
private HashMap<String/* brokerAddr */, List<String>/* Filter Server */> filterServerTable; //broker上過濾服務器地址列表