問題現象
RocketMQ3.2.2版本,測試時嘗試發送消息時自動創建Topic,設置了隊列數量爲8:
producer.setDefaultTopicQueueNums(8);
同時設置broker服務器的配置文件broker.properties:
defaultTopicQueueNums=16
但實際創建後從控制檯及後臺打印代碼觀察到該Topic只創建了4個隊列,反覆重試確認發送消息時自動創建Topic,最大創建4個隊列。
查找原因,服務端與客戶端配置對比
閱讀源碼,在TopicConfigManager的createTopicInSendMessageMethod方法,有對比TopicConfig對象中的隊列數和客戶端設定隊列數,並選擇其中較小者爲新建Topic隊列數的邏輯:
int queueNums = clientDefaultTopicQueueNums > defaultTopicConfig.getWriteQueueNums() ? defaultTopicConfig.getWriteQueueNums() : clientDefaultTopicQueueNums;
定位問題在服務端TopicConfig
打印這兩個變量:
客戶隊列數clientDefaultTopicQueueNums爲8,正確;
而defaultTopicConfig.getWriteQueueNums()爲4,而非broker.properties中設定的16;
由可以確定是問題出在defaultTopicConfig上。
defaultTopicConfig數據來源
defaultTopicConfig是從ConcurrentHashMap<String,TopicConfig> topicConfigTable中取得,如下:
TopicConfig defaultTopicConfig =this.topicConfigTable.get(defaultTopic);
而defaultTopic默認值爲MixAll.DEFAULT_TOPIC=“TBW102”。
爲了確認topicConfigTable中的爲MixAll.DEFAULT_TOPIC的Config對象屬性值的真實來源,繼續閱讀源碼,發現borker有兩處改寫DEFAULT_TOPIC的Config對象的位置:
一處是TopicConfigManager的構造方法,在borker服務器啓動時運行,會讀取broker.properties裏的配置,此時DEFAULT_TOPIC的Config對象裏的DefaultQueueNums爲正確的我所配置的16;
一處是在BrokerController的initialize方法裏調用了TopicConfigManager.load方法:
該load方法繼承自ConfigManager類,讀取了$ROCKETMQ_HOME\store\config下保存的配置信息,並調用抽象方法decode(),配置信息作爲json字符串參數傳入到decode();
TopicConfigManager類的decode實現方法裏,讀取了$ROCKETMQ_HOME\store\config\topics.json裏的配置信息,並覆寫到topicConfigTable,而此前生成的topics.json的“TBW102”的配置信息裏的writeQueueNums及readQueueNums均爲4。
最終結論
在發送消息自動創建Topic時,對於此前已運行的borker服務器,修改配置文件的defaultTopicQueueNums屬性的值不起作用。
因爲發送消息自動創建Topic的實現裏,隊列數取小對比操作的變量——defaultTopicConfig寫在topics.json的配置信息裏的writeQueueNums及readQueueNums,讀取自Topics.json,所以即使修改配置文件並重啓borker服務器後也不會改變。而服務端最終會用topics.json的值覆蓋發送消息自動創建Topic時的TopicConfig配置信息。
阿里的解釋
隊列是資源,所以管控權會放到服務器。
但是每個用戶的默認策略又不一樣,所以會有一個默認topic作爲模板,在未創建默認topic前,系統會自動創建一個。
這個可以佔到運維的角度思考,例如你運維了10個集羣,爲1000個用戶服務。有些用戶需要動態的創建topic,但是不能給他足夠的權限,想創建多少創建多少。
所有會給他一個模板的topic,就是defaultTopic,動態創建topic繼承於defaultTopic配置,隊列數不能超過defaultTopic。
解決辦法
通過producer.createTopic方法創建(實現的方式是將創建命發送到控制檯),可以創建成功,但會報應答超時失敗,原因未查;
通過控制檯方式創建;
修改metaq源碼重新編譯borker,使用broker的配置信息覆蓋defaultTopic的配置信息。