rockeMQ-producer源碼

DefaultMQProducerImpl

啓動

start方法

  1. producerGroup如果不是CLIENT_INNER_PRODUCER,並且intanceName=DEFAULT,則把instanceName改爲PID

  2. mQClientFactory是一個MQClientInstance對象,由MQClientManager管理,這是一個單例,其中ConcurrentMap<String/* clientId */, MQClientInstance> factoryTable 用來維護創建的MQClientInstance對象。

    1. 創建mQClientFactory時首先根據創建clientId=ip+instanceName+unitName,根據這個id在factoryTable中獲取對象
    2. 如果爲空,則創建一個新的對象,放入factoryTable中
  3. 註冊producer到mQClientFactory

    1. mQClientFactory中維護一個ConcurrentMap<String/* group */, MQProducerInner> producerTable對象緩存創建的producer
    2. 根據當前producer的producerGroup從map中獲取,沒有則直接將當前producer放入map中,如果producerGroup已存在則會提示producerGroup已存在
  4. DefaultMQProducerImpl 維護一個ConcurrentMap<String/* topic */, TopicPublishInfo> topicPublishInfoTable,緩存topic和TopicPublishInfo,新建一個topicPublishInfoTable放入table中

  5. 調用mQClientFactory的start方法,啓動流程包括:

    1. 獲取nameServer地址,如果沒有則用http請求從配置url中獲取
    	this.mQClientAPIImpl.fetchNameServerAddr();
    
    1. 啓動mqClientAPIImpl
    // Start request-response channel
    this.mQClientAPIImpl.start();
    
    1. 啓動各種定時任務
    // Start various schedule tasks
    this.startScheduledTask();
    

    定時任務包括:

     * fetchNameServerAddr
     * updateTopicRouteInfoFromNameServer
     * cleanOfflineBroker&sendHeartbeatToAllBrokerWithLock
     * persistAllConsumerOffset
     * adjustThreadPool
    
    1. 啓動pull service線程
    // Start pull service
    this.pullMessageService.start();
    
    1. 啓動負載均衡線程
    // Start rebalance service
    this.rebalanceService.start();
    
    1. 啓動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(默認)

查找路由信息

  1. 在本地topicPublishInfoTable緩存中根據topic獲取

  2. 如果沒有或者狀態不ok,則updateTopicRouteInfoFromNameServer,從nameServer根據topic獲取並放入緩存,拿到TopicPublishInfo對象,轉爲topicRouteData對象

  3. 路由信息在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上過濾服務器地址列表
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章