RocketMQ NameServer 核心源碼解析
帶著問題 往下看 (namesrv)
- 我們?cè)趯懡M件的時(shí)候 怎么管理version
- 如果現(xiàn)在讓你 維護(hù)一個(gè) 各個(gè)jar包公用的屬性
- System.exit(-1); 0 -1 -2 各種數(shù)都是干什么的,什么時(shí)候 用哪個(gè)
- 環(huán)境變量如果不想使用 ROCKETMQ_HOME, 想變?yōu)?xxx 這怎么做,能做么?
- 我們啟動(dòng)broker 老是用 -n ip:9876 9876是什么,我們可以改變么?怎么改
- 大家如果想 把命令啟動(dòng)帶著的 -c -p等參數(shù)放到 我們的屬性中,怎么寫代碼?
- 如果我們想 自己設(shè)置使用的log 組件,怎么辦
- 遍歷 Field[] 的時(shí)候 想跳過 static的屬性 怎么寫代碼?
- 多個(gè)對(duì)象的 屬性需要進(jìn)行聚合到一個(gè)對(duì)象中,要是你 怎么寫
- KVConfigManager 有什么作用,怎么保證的 并發(fā)操作的數(shù)據(jù)正確性?你感覺有什么問題么?
- KVConfigManager 怎么保證的 持久化?
- 怎么在 并發(fā)操作的時(shí)候 保證數(shù)據(jù)的安全性?
- 方法的參數(shù) 使用final 有什么用?
- 怎么判斷的broker 是不是master
- netty 怎么讓nameserver 通知broker 信息的。
- nameserver 是否存活的判斷標(biāo)準(zhǔn)是什么? 能修改么? 怎么修改
- Runtime.getRuntime().addShutdownHook 有什么用,沒有不行么?
- @ImportantField 干什么的? 什么時(shí)候 使用
- 在同一臺(tái)計(jì)算機(jī)上部署多個(gè)代理時(shí) 想?yún)^(qū)分日志路徑 用哪個(gè)參數(shù),調(diào)成什么?
- broker 為什么 -p 和 -m 同時(shí)有的時(shí)候 -m的總是不生效呢?
請(qǐng)思考下 寫寫你的答案 再往下看
nameserver 啟動(dòng)的邏輯
nameserver 功能
- 管理broker 集群
- 屬于注冊(cè)中心 業(yè)務(wù)端 和nameserver 進(jìn)行連接,獲取broker地址
- 負(fù)責(zé)維護(hù)broker 連接/心跳/監(jiān)控
nameserver 問題解答
我們?cè)趯懡M件的時(shí)候 怎么管理version
一方面是 在父類的 pom.xml 通過 進(jìn)行 控制版本,然后 業(yè)務(wù)端通過
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.xxx</groupId>
<artifactId>xxx</artifactId>
<version>4.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
這是第一個(gè) ,第二個(gè) 是 rocketmq 這種 在common 包下面 新建一個(gè) MQVersion 管理版本
這里會(huì)有一個(gè)問題,那這個(gè)版本管理 我用在哪里啊,不用不行么?
- 為了方便測試,測試的時(shí)候 可能因?yàn)榘姹居胁町?導(dǎo)致的問題。指定version 就沒有這個(gè)問題了 2 broker 操作也是,(其實(shí)一句話 為了之后的版本兼容)比如
if (version < MQVersion.Version.V3_0_7_SNAPSHOT.ordinal()) {
result.setCode(ResponseCode.SYSTEM_ERROR);
result.setRemark("the client does not support this feature. version="
+ MQVersion.getVersionDesc(version));
log.warn("[get-consumer-status] the client does not support this feature. channel={}, version={}",
RemotingHelper.parseChannelRemoteAddr(entry.getKey()), MQVersion.getVersionDesc(version));
return result;
} else if (UtilAll.isBlank(originClientId) || originClientId.equals(clientId)) {
}
如果現(xiàn)在讓你 維護(hù)一個(gè) 各個(gè)jar包公用的屬性
1 在common包搞一個(gè) 公共的實(shí)體類 隨時(shí)用隨時(shí)取唄,大不了就一個(gè)map 然后就put get
2 System.setProperty 底層就是全局 map 進(jìn)行put get
extends Hashtable<Object,Object>
環(huán)境變量如果不想使用 ROCKETMQ_HOME, 想變?yōu)?xxx 這怎么做,能做么?
設(shè)置 rocketmq.home.dir=xxx
我們啟動(dòng)broker 老是用 -n ip:9876 9876是什么,我們可以改變么?怎么改
nettyServerConfig.setListenPort(9876);
代碼指定 的netty 監(jiān)聽端口,一般情況不改
大家如果想 把命令啟動(dòng)帶著的 -c -p等參數(shù)放到 我們的屬性中,怎么寫代碼?
MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);
這是先把commandLine 轉(zhuǎn)變?yōu)?Properties 對(duì)象,然后調(diào)用 namesrvConfig 反射方法 賦值
如果我們想 自己設(shè)置使用的log 組件,怎么辦
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(lc); lc.reset(); configurator.doConfigure(namesrvConfig.getRocketmqHome() + "/conf/logback_namesrv.xml");
遍歷 Field[]
遍歷 Field[]的時(shí)候 想跳過 static的屬性 怎么寫代碼?
(field.getModifiers() & 0x00000008) != 0 如果為true 就是 static false為 非static
多個(gè)對(duì)象的 屬性需要進(jìn)行聚合到一個(gè)對(duì)象中,要是你 怎么寫
for (Entry<Object, Object> next : from.entrySet()) {
Object fromObj = next.getValue(), toObj = to.get(next.getKey());
if (toObj != null && !toObj.equals(fromObj)) {
log.info("Replace, key: {}, value: {} -> {}", next.getKey(), toObj, fromObj);
}
to.put(next.getKey(), fromObj);
}
因?yàn)?可能同時(shí)操作這個(gè)對(duì)象 導(dǎo)致 數(shù)據(jù)不一致 ,所以要加上 讀寫鎖的 寫鎖
KVConfigManager 有什么作用
KVConfigManager 有什么作用,怎么保證的 并發(fā)操作的數(shù)據(jù)正確性?你感覺有什么問題么?
是 kv 配置的管理器,主要是
HashMap<String/* Namespace */, HashMap<String/* Key */, String/* Value */>> configTable
以后寫map 也要像這種方式 寫注釋。
//讀取的是 ./namesrv/kvConfig.json
kvConfigPath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "kvConfig.json";
行吧 ,現(xiàn)在還不知道 這些kv的作用,先看看怎么存儲(chǔ)的,到用的時(shí)候 我們接上,先知道 kv 存儲(chǔ)在KVConfigManager類 configTable 屬性中
putKVConfig 使用的 ReentrantReadWriteLock 的寫鎖 保證數(shù)據(jù)一致性,如果map的key 存在了,不會(huì)進(jìn)行覆蓋,而是 跳過。
KVConfigManager 持久化
KVConfigManager 怎么保證的 持久化?
執(zhí)行過 上面的 那些方法,執(zhí)行 persist ,加讀鎖,如下圖

怎么在 并發(fā)操作的時(shí)候 保證數(shù)據(jù)的安全性?
一方面 是 不可變類,其中返回屬性的時(shí)候 要進(jìn)行copy 簡單來說 就是我通過get 方法出去的 對(duì)象 是 copy的對(duì)象,而不是 原來的對(duì)象,防止 外面通過引用 修改 屬性值,把我們的對(duì)象 屬性 進(jìn)行修改。
方法的參數(shù) 使用final 有什么用?
- 確保,不會(huì)也不能對(duì)于參數(shù)進(jìn)行修改,保證了調(diào)用發(fā)起方數(shù)據(jù)的安全;
- 避免在方法體中修改參數(shù),引起不必要的錯(cuò)誤
- 程序員工作不是一個(gè)人的工作,你設(shè)置為final,別人將來維護(hù)的時(shí)候一看就知道這個(gè)變量不能修改,而不需要去記憶這個(gè)是不能變化的值,是常量。這個(gè)是代碼規(guī)范。
broker 是不是master判斷
怎么判斷的broker 是不是master
//0 == brokerId MixAll.MASTER_ID == brokerId
這個(gè)其實(shí)可以 抽出來一個(gè)公共的方法, 方便之后的修改
netty 怎么讓nameserver 通知broker 信息的。
netty 保存的 channel 到時(shí)候用了 直接從map 獲取 然后發(fā)送消息
nameserver 是否存活的判斷標(biāo)準(zhǔn)是什么? 能修改么? 怎么修改
BROKER_CHANNEL_EXPIRED_TIME = 1000 * 60 * 2
static final 寫死的,如果 最后一次心跳時(shí)間 + 2分鐘 都小于System.currentTimeMillis() 執(zhí)行刪除操作
- 關(guān)閉 netty channel
- brokerLiveTable 刪除對(duì)應(yīng)的實(shí)例
這是一個(gè)定時(shí)任務(wù) 從項(xiàng)目 啟動(dòng)5s之后 ,每10s執(zhí)行一次,說明 對(duì)broker的感知 會(huì)有些許 延遲。(最大也就 20s,一般10s以內(nèi)感知)
Runtime.getRuntime().addShutdownHook 有什么用,沒有不行么?
當(dāng)程序正常退出,系統(tǒng)調(diào)用 System.exit方法或虛擬機(jī)被關(guān)閉時(shí)才會(huì)執(zhí)行添加的shutdownHook線程。其中shutdownHook是一個(gè)已初始化但并不有啟動(dòng)的線程,當(dāng)jvm關(guān)閉的時(shí)候,會(huì)執(zhí)行系統(tǒng)中已經(jīng)設(shè)置的所有通過方法addShutdownHook添加的鉤子,當(dāng)系統(tǒng)執(zhí)行完這些鉤子后,jvm才會(huì)關(guān)閉。所以可通過這些鉤子在jvm關(guān)閉的時(shí)候進(jìn)行內(nèi)存清理、資源回收等工作。
@ImportantField
@ImportantField 干什么的? 什么時(shí)候 使用
最后的true 代表 是否只打印關(guān)鍵屬性,寫@ImportantField的 就一定會(huì)打,沒有這個(gè)注解的就不打印了
MixAll.printObjectProperties(console, brokerConfig, true);
在同一臺(tái)計(jì)算機(jī)上部署多個(gè)代理時(shí) 想?yún)^(qū)分日志路徑 用哪個(gè)參數(shù),調(diào)成什么?
isolateLogEnable 改為 true
if (brokerConfig.isIsolateLogEnable()) {
System.setProperty("brokerLogDir", brokerConfig.getBrokerName() + "_" + brokerConfig.getBrokerId());
}
if (brokerConfig.isIsolateLogEnable() && messageStoreConfig.isEnableDLegerCommitLog()) {
System.setProperty("brokerLogDir", brokerConfig.getBrokerName() + "_" + messageStoreConfig.getdLegerSelfId());
}
broker 為什么 -p 和 -m 同時(shí)有的時(shí)候 -m的總是不生效呢?
無論是 -p 還是 -m 都是print 輸出,本來就是希望打印日志,然后進(jìn)程停止。
opt = new Option("p", "printConfigItem", false, "Print all config item");
opt = new Option("m", "printImportantConfig", false, "Print important config item");
總結(jié)
這些 只是 namestr 的NamesrvController 初始化,更多關(guān)于RocketMQ NameServer 解析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot+ECharts是如何實(shí)現(xiàn)數(shù)據(jù)可視化的
今天帶大家學(xué)習(xí)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著SpringBoot+ECharts怎么實(shí)現(xiàn)數(shù)據(jù)可視化展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
SpringBoot實(shí)現(xiàn)單文件與多文件上傳功能
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)單文件與多文件上傳功能,Spring?MVC對(duì)文件上傳做了簡化,而在Spring?Boot中對(duì)此做了更進(jìn)一步的簡化,文件上傳變得更為方便,下面開始演示,需要的小伙伴可以參考一下,希望對(duì)你有所幫助2022-01-01
Java基本數(shù)據(jù)類型與類型轉(zhuǎn)換實(shí)例分析
這篇文章主要介紹了Java基本數(shù)據(jù)類型與類型轉(zhuǎn)換,結(jié)合實(shí)例形式分析了Java基本數(shù)據(jù)類型分類、用法,類型轉(zhuǎn)換及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2020-04-04
Java8中對(duì)于LocalDateTime的序列化和反序列化問題
這篇文章主要介紹了Java8中對(duì)于LocalDateTime的序列化和反序列化問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Maven依賴中scope的runtime和provied的區(qū)別及說明
這篇文章主要介紹了Maven依賴中scope的runtime和provied的區(qū)別及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11

