hi 大家好 上兩章介紹了namesrv的啓動和註冊過程,有什麼不對的地方歡迎大家吐槽,接着開始分析broker吧
有些地方畫不下了 通過分析看細節吧..
1,createBrokerController
System.setProperty(RemotingCommand.RemotingVersionKey, Integer.toString(MQVersion.CurrentVersion));
// Socket發送緩衝區大小
if (null == System.getProperty(NettySystemConfig.SystemPropertySocketSndbufSize)) {
NettySystemConfig.SocketSndbufSize = 131072;
}
默認發送緩衝區大小128M
// Socket接收緩衝區大小
if (null == System.getProperty(NettySystemConfig.SystemPropertySocketRcvbufSize)) {
NettySystemConfig.SocketRcvbufSize = 131072;
}
默認接收緩衝區大小128M
// 檢測包衝突
PackageConflictDetect.detectFastjson();
// 解析命令行
Options options = ServerUtil.buildCommandlineOptions(new Options());
commandLine = ServerUtil.parseCmdLine("mqbroker", args, buildCommandlineOptions(options),
new PosixParser());
if (null == commandLine) {
System.exit(-1);
return null;
}
2,final BrokerConfig brokerConfig = new BrokerConfig();
private String rocketmqHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY,
System.getenv(MixAll.ROCKETMQ_HOME_ENV));
獲取rocketMq目錄
@ImportantField
private String namesrvAddr = System.getProperty(MixAll.NAMESRV_ADDR_PROPERTY,
System.getenv(MixAll.NAMESRV_ADDR_ENV));
獲取namesrc地址
@ImportantField
private String brokerIP1 = RemotingUtil.getLocalAddress();
獲取本地地址
private String brokerIP2 = RemotingUtil.getLocalAddress();
獲取本地地址
@ImportantField
private String brokerName = localHostName();
獲取broker hostname
@ImportantField
private String brokerClusterName = "DefaultCluster";
默認集羣名稱
@ImportantField
private long brokerId = MixAll.MASTER_ID;
master集羣ID 必須爲0
private int brokerPermission = PermName.PERM_READ | PermName.PERM_WRITE;
broker權限 默認讀與寫
private int defaultTopicQueueNums = 8;
默認隊列數量
// 自動創建Topic功能是否開啓(線上建議關閉)
@ImportantField
private boolean autoCreateTopicEnable = true;
// 自動創建以集羣名字命名的Topic功能是否開啓
private boolean clusterTopicEnable = true;
// 自動創建以服務器名字命名的Topic功能是否開啓
private boolean brokerTopicEnable = true;
// 自動創建訂閱組功能是否開啓(線上建議關閉)
@ImportantField
private boolean autoCreateSubscriptionGroup = true;
private int sendMessageThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 4;
發送消息線程池數量
private int pullMessageThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2;
訂閱消息線程池數量
private int adminBrokerThreadPoolNums = 16;
adminBroker 線程池數量 各自獨立的線程池 做到線程池隔離
private int clientManageThreadPoolNums = 16;
clientManage線程池數量
private int flushConsumerOffsetInterval = 1000 * 5;
flush消費端 文件偏移時間戳 默認5秒
private int flushConsumerOffsetHistoryInterval = 1000 * 60;
flush消費端 歷史文件偏移時間戳 默認1
// 是否拒絕接收事務消息
@ImportantField
private boolean rejectTransactionMessage = false;
// 是否從地址服務器尋找Name Server地址,正式發佈後,默認值爲false
@ImportantField
private boolean fetchNamesrvAddrByAddressServer = false;
// 發送消息對應的線程池阻塞隊列size
private int sendThreadPoolQueueCapacity = 100000;
// 訂閱消息對應的線程池阻塞隊列size
private int pullThreadPoolQueueCapacity = 100000;
// 過濾服務器數量
private int filterServerNums = 0;
// Consumer訂閱消息時,Broker是否開啓長輪詢
private boolean longPollingEnable = true;
// 如果是短輪詢,服務器掛起時間
private long shortPollingTimeMills = 1000;
// notify consumerId changed 開關
private boolean notifyConsumerIdsChangedEnable = true;
// slave 是否需要糾正位點
private boolean offsetCheckInSlave = false;
3,final NettyServerConfig nettyServerConfig = new NettyServerConfig();
netty 服務配置
private int listenPort = 8888; 監聽端口
private int serverWorkerThreads = 8;Netty服務工作線程數量
private int serverCallbackExecutorThreads = 0;Netty服務異步回調線程池線程數量
private int serverSelectorThreads = 3;Netty Selector線程數量
private int serverOnewaySemaphoreValue = 256;控制單向的信號量 一次請求沒有響應
private int serverAsyncSemaphoreValue = 64;控制異步信號量
private int serverChannelMaxIdleTimeSeconds = 120;服務空閒心跳檢測時間間隔 單位秒
private int serverSocketSndBufSize = NettySystemConfig.SocketSndbufSize;
Netty發送緩衝區大小
private int serverSocketRcvBufSize = NettySystemConfig.SocketRcvbufSize;
Netty接受緩衝區大小
private boolean serverPooledByteBufAllocatorEnable = false;是否使用Netty內存池
4,final NettyClientConfig nettyClientConfig = new NettyClientConfig();
private int clientWorkerThreads = 4;Netty客戶端工作線程
private int clientCallbackExecutorThreads = Runtime.getRuntime().availableProcessors();
Netty服務異步回調線程池線程數量
private int clientOnewaySemaphoreValue = NettySystemConfig.ClientOnewaySemaphoreValue;
控制單向的信號量 一次請求沒有響應
private int clientAsyncSemaphoreValue = NettySystemConfig.ClientAsyncSemaphoreValue;
控制異步信號量
private long connectTimeoutMillis = 3000;
連接超時時間
private long channelNotActiveInterval = 1000 * 60;
掃描channel未激活時間戳
private int clientChannelMaxIdleTimeSeconds = 120;
客戶端閒心跳檢測時間間隔 單位秒
private int clientSocketSndBufSize = NettySystemConfig.SocketSndbufSize;
客戶端發送緩衝區大小
private int clientSocketRcvBufSize = NettySystemConfig.SocketRcvbufSize;
客戶端接受緩衝區大小
private boolean clientPooledByteBufAllocatorEnable = false;
客戶端是否支持netty內存池
nettyServerConfig.setListenPort(10911);
監聽端口
5,final MessageStoreConfig messageStoreConfig = new MessageStoreConfig();
// 存儲跟目錄
@ImportantField
private String storePathRootDir = System.getProperty("user.home") + File.separator + "store";
// CommitLog存儲目錄
@ImportantField
private String storePathCommitLog = System.getProperty("user.home") + File.separator + "store"
+ File.separator + "commitlog";
// CommitLog每個文件大小 1G
private int mapedFileSizeCommitLog = 1024 * 1024 * 1024;
// ConsumeQueue每個文件大小 默認存儲30W條消息
private int mapedFileSizeConsumeQueue = 300000 * ConsumeQueue.CQStoreUnitSize;
// CommitLog刷盤間隔時間(單位毫秒)
@ImportantField
private int flushIntervalCommitLog = 1000;
// 是否定時方式刷盤,默認是實時刷盤
@ImportantField
private boolean flushCommitLogTimed = false;
// ConsumeQueue刷盤間隔時間(單位毫秒)
private int flushIntervalConsumeQueue = 1000;
// 清理資源間隔時間(單位毫秒)
private int cleanResourceInterval = 10000;
// 刪除多個CommitLog文件的間隔時間(單位毫秒)
private int deleteCommitLogFilesInterval = 100;
// 刪除多個ConsumeQueue文件的間隔時間(單位毫秒)
private int deleteConsumeQueueFilesInterval = 100;
// 強制刪除文件間隔時間(單位毫秒)
private int destroyMapedFileIntervalForcibly = 1000 * 120;
// 定期檢查Hanged文件間隔時間(單位毫秒)
private int redeleteHangedFileInterval = 1000 * 120;
// 何時觸發刪除文件, 默認凌晨4點刪除文件
@ImportantField
private String deleteWhen = "04";
// 磁盤空間最大使用率
private int diskMaxUsedSpaceRatio = 75;
// 文件保留時間(單位小時)
@ImportantField
private int fileReservedTime = 72;
// 寫消息索引到ConsumeQueue,緩衝區高水位,超過則開始流控
private int putMsgIndexHightWater = 600000;
// 最大消息大小,默認512K
private int maxMessageSize = 1024 * 512;
// 重啓時,是否校驗CRC
private boolean checkCRCOnRecover = true;
// 刷CommitLog,至少刷幾個PAGE
private int flushCommitLogLeastPages = 4;
// 刷ConsumeQueue,至少刷幾個PAGE
private int flushConsumeQueueLeastPages = 2;
// 刷CommitLog,徹底刷盤間隔時間
private int flushCommitLogThoroughInterval = 1000 * 10;
// 刷ConsumeQueue,徹底刷盤間隔時間
private int flushConsumeQueueThoroughInterval = 1000 * 60;
// 最大被拉取的消息字節數,消息在內存
@ImportantField
private int maxTransferBytesOnMessageInMemory = 1024 * 256;
// 最大被拉取的消息個數,消息在內存
@ImportantField
private int maxTransferCountOnMessageInMemory = 32;
// 最大被拉取的消息字節數,消息在磁盤
@ImportantField
private int maxTransferBytesOnMessageInDisk = 1024 * 64;
// 最大被拉取的消息個數,消息在磁盤
@ImportantField
private int maxTransferCountOnMessageInDisk = 8;
// 命中消息在內存的最大比例
@ImportantField
private int accessMessageInMemoryMaxRatio = 40;
// 是否開啓消息索引功能
@ImportantField
private boolean messageIndexEnable = true;
private int maxHashSlotNum = 5000000;
private int maxIndexNum = 5000000 * 4;
private int maxMsgsNumBatch = 64;
// 是否使用安全的消息索引功能,即可靠模式。
// 可靠模式下,異常宕機恢復慢
// 非可靠模式下,異常宕機恢復快
@ImportantField
private boolean messageIndexSafe = false;
// HA功能
private int haListenPort = 10912;
private int haSendHeartbeatInterval = 1000 * 5;
private int haHousekeepingInterval = 1000 * 20;
private int haTransferBatchSize = 1024 * 32;
// 如果不設置,則從NameServer獲取Master HA服務地址
@ImportantField
private String haMasterAddress = null;
// Slave落後Master超過此值,則認爲存在異常
private int haSlaveFallbehindMax = 1024 * 1024 * 256;
@ImportantField
private BrokerRole brokerRole = BrokerRole.ASYNC_MASTER;
@ImportantField
private FlushDiskType flushDiskType = FlushDiskType.ASYNC_FLUSH;
// 同步刷盤超時時間
private int syncFlushTimeout = 1000 * 5;
// 定時消息相關
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
private long flushDelayOffsetInterval = 1000 * 10;
// 磁盤空間超過90%警戒水位,自動開始刪除文件
@ImportantField
private boolean cleanFileForciblyEnable = true;
6,// 如果是slave,修改默認值
if (BrokerRole.SLAVE == messageStoreConfig.getBrokerRole()) {
int ratio = messageStoreConfig.getAccessMessageInMemoryMaxRatio() - 10;
messageStoreConfig.setAccessMessageInMemoryMaxRatio(ratio);
}
如果是master broker命中消息在內存的最大比例是40
如果是slave broker命中消息在內存的最大比例是30
7,String namesrvAddr = brokerConfig.getNamesrvAddr();
if (null != namesrvAddr) {
try {
String[] addrArray = namesrvAddr.split(";");
if (addrArray != null) {
for (String addr : addrArray) {
RemotingUtil.string2SocketAddress(addr);
}
}
}
catch (Exception e) {
System.out
.printf(
"The Name Server Address[%s] illegal, please set it as follows, \"127.0.0.1:9876;192.168.0.1:9876\"\n",
namesrvAddr);
System.exit(-3);
}
}
檢測Name Server地址設置是否正確 IP:PORT
7, switch (messageStoreConfig.getBrokerRole()) {
case ASYNC_MASTER:
case SYNC_MASTER:
brokerConfig.setBrokerId(MixAll.MASTER_ID);
break;
case SLAVE:
if (brokerConfig.getBrokerId() <= 0) {
System.out.println("Slave's brokerId must be > 0");
System.exit(-3);
}
break;
default:
break;
}
判斷如果是Master Broker Id必須是0 ,如果是Slave Broker Id必須大於0
8,// Master監聽Slave請求的端口,默認爲服務端口+1
messageStoreConfig.setHaListenPort(nettyServerConfig.getListenPort() + 1);
// 初始化Logback
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(lc);
lc.reset();
configurator.doConfigure(brokerConfig.getRocketmqHome() + "/conf/logback_broker.xml");
log = LoggerFactory.getLogger(LoggerName.BrokerLoggerName);
9,final BrokerController controller = new BrokerController(
brokerConfig,
nettyServerConfig,
nettyClientConfig,
messageStoreConfig);
初始化服務控制對象
this.brokerConfig = brokerConfig; broker配置
this.nettyServerConfig = nettyServerConfig;netty服務配置
this.nettyClientConfig = nettyClientConfig;netty客戶端配置
this.messageStoreConfig = messageStoreConfig;消息存儲配置
this.consumerOffsetManager = new ConsumerOffsetManager(this);
消費進度管理
this.topicConfigManager = new TopicConfigManager(this);
Topic配置管理
this.pullMessageProcessor = new PullMessageProcessor(this);
拉消息請求處理
this.pullRequestHoldService = new PullRequestHoldService(this);
拉消息請求管理,如果拉不到消息,則在這裏Hold住,等待消息到來
this.consumerIdsChangeListener = new DefaultConsumerIdsChangeListener(this);
ConsumerId列表變化,通知所有Consumer
this.consumerManager = new ConsumerManager(this.consumerIdsChangeListener);
Consumer連接、訂閱關係管理
this.producerManager = new ProducerManager();
管理Producer組及各個Producer連接
this.clientHousekeepingService = new ClientHousekeepingService(this);
定期檢測客戶端連接,清除不活動的連接
this.broker2Client = new Broker2Client(this);
Broker主動調用客戶端接口
this.subscriptionGroupManager = new SubscriptionGroupManager(this);
用來管理訂閱組,包括訂閱權限等
this.brokerOuterAPI = new BrokerOuterAPI(nettyClientConfig);
Broker對外調用的API封裝
this.filterServerManager = new FilterServerManager(this);
過濾服務管理
if (this.brokerConfig.getNamesrvAddr() != null) {
this.brokerOuterAPI.updateNameServerAddressList(this.brokerConfig.getNamesrvAddr());
log.info("user specfied name server address: {}",this.brokerConfig.getNamesrvAddr());
}
更新namesrv地址,防止存在存留數據
this.slaveSynchronize = new SlaveSynchronize(this);
Slave從Master同步信息(非消息)
this.sendThreadPoolQueue =
new LinkedBlockingQueue<Runnable>(this.brokerConfig.getSendThreadPoolQueueCapacity());
初始化發送消息對應的線程池阻塞隊列size
this.pullThreadPoolQueue =
new LinkedBlockingQueue<Runnable>(this.brokerConfig.getPullThreadPoolQueueCapacity());
初始化訂閱消息對應的線程池阻塞隊列size
this.brokerStatsManager = new BrokerStatsManager(this.brokerConfig.getBrokerClusterName());
broker 狀態管理
this.setStoreHost(new InetSocketAddress(this.getBrokerConfig().getBrokerIP1(), this
.getNettyServerConfig().getListenPort()));
暫時沒發現在哪用,等用到了在說
由於篇幅的問題 請看第三章註冊過程2