問題現象
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的配置信息。