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è)版本管理 我用在哪里啊,不用不行么?
- 為了方便測(cè)試,測(cè)試的時(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 簡(jiǎn)單來說 就是我通過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)文章
淺談為什么Java中1000==1000為false而100==100為true
這篇文章主要介紹了淺談為什么Java中1000==1000為false而100==100為true,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09SpringCloud?微服務(wù)數(shù)據(jù)權(quán)限控制的實(shí)現(xiàn)
這篇文章主要介紹的是權(quán)限控制的數(shù)據(jù)權(quán)限層面,意思是控制可訪問數(shù)據(jù)資源的數(shù)量,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-11-11如何用注解的方式實(shí)現(xiàn)Mybatis插入數(shù)據(jù)時(shí)返回自增的主鍵Id
這篇文章主要介紹了如何用注解的方式實(shí)現(xiàn)Mybatis插入數(shù)據(jù)時(shí)返回自增的主鍵Id,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07Java網(wǎng)絡(luò)編程之URL+URLconnection使用方法示例
這篇文章主要介紹了Java網(wǎng)絡(luò)編程之URL+URLconnection使用方法示例,還是比較不錯(cuò)的,這里分享給大家,供需要的朋友參考。2017-11-11Java Netty HTTP服務(wù)實(shí)現(xiàn)過程解析
這篇文章主要介紹了Java Netty HTTP服務(wù)實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08使用Java注解和反射實(shí)現(xiàn)JSON字段自動(dòng)重命名
這篇文章主要介紹了如何使用Java注解和反射實(shí)現(xiàn)JSON字段自動(dòng)重命名,文中通過代碼示例和圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-08-08SpringBoot如何啟動(dòng)自動(dòng)加載自定義模塊yml文件(PropertySourceFactory)
這篇文章主要介紹了SpringBoot如何啟動(dòng)自動(dòng)加載自定義模塊yml文件(PropertySourceFactory),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07