上篇文章主要梳理了NameServer的启动器和配置信息,并复习了JVM中的关闭钩子这个知识点。这篇文章看下NameServer的其他模块。建议带着如下三个问题阅读:
NameServer管理哪些信息?如何管理的?
NameServer中对Netty的使用案例?
NameServer中对Java并发编程使用案例?
一、NamesrvController
作用:NameServer模块的控制器
主要属性:
namesrvConfig:name server的配置信息
nettyServerConfig:name server中作为netty服务端的配置
scheduledExecutorService:调度线程池,用于:(1)周期性检查broker信息;(2)周期性打印路由信息;这两个检查每隔5秒交替进行。
kvConfigManager:name server配置的操作接口
routeInfoManager:name server路由信息的操作接口
remotingServer:netty服务器
brokerHousekeepingService:监听连接的broker的通道的关闭或异常事件,用于清理broker信息;
remotingExecutor:服务端处理请求的线程池
代码如下:
主要方法
initialize:初始化
registerProcessor:注册处理器
其他还有:构造方法、start方法、shutdown方法
Java并发:
Executors.newFixedThreadPool(),用于创建固定数量的线程池,根据线程池的运行原理:线程池启动时候没有线程,当新任务到来时就创建线程处理;由于coreSize和maxSize设置为相同大小,如果任务来的时候线程已经达到coreSize,就直接放入等待队列;keepAlive设置为0,目的是让线程数不会超过coreSize;blockqueue设置为LinkedBlockingQueue,表示是无界队列,最多可以放Integer.MAX_VALUE个任务。
周期线程池
NameServerController中使用了调度线程池,我们看下创建一个调度线程池的方法,即Executors.newSingleThreadScheduledExecutor(),该方法的定义如下所示:
这种线程池的创建又委托给了DelegatedScheduledExecutorService类,这里为什么这么设计,不是太理解。不过可以看下真正创建调度线程池的代码:
上面这个方法,关键在于两点:(1)maxSize选了Integer.MAX_VALUE;(2)任务队列使用了延迟队列;再回头去看那个委托类的代码,就可以明白,委托类包装了ScheduledExecutorService执行器,提供了延迟或周期执行的接口。
找到上面几个主要类和接口的类图,再综合上面的代码,可以这么理解:Executors是一个工具类,提供了生成不同的线程池的工厂方法,其中包括newSingleThreadScheduledExecutor方法,由于ScheduledExecutorService扩展了ExecutorService接口,同时又想重用AbstractExecutorService中的一些方法,因此需要一个委托类,将ExecutorService和ScheduledExecutorService的功能整合在一个类中。
Netty
RemotingServer是name server中的通信服务端,在name controller初始化name server模块的时候,会将name server的请求处理器注册到netty服务器上。
二、DefaultRequestProcessor
在NameServerController中会注册请求处理器,那么name server的请求处理器实现了哪些接口呢,请看代码:
从这个代码中可以看出两个方面的内容:
如何使用Netty处理网络请求。关键数据结构:(1)RemotingCommand:自定义的协议,携带请求参数和响应(2)ChannelHandlerContext:netty的数据结构,携带channel相关的信息。设计模型:processRequest:通过请求码进行请求转发;
请求处理方法(跟协议相关,具体参见remote模块)(1)processRequest:请求分发;(2)putKVConfig:将配置信息放在内存中;(3)getKVConfig:返回配置信息(4)deleteKVConfig:删除配置信息;(5)注册broker,支持两个注册方式:带过滤服务的(MQ版本在V311之后的)、不带过滤服务的,等其他处理方法。
三、BrokerHousekeepingService
该模块实现了ChannelEventListener接口,每个broker都会跟name server建立一个连接通道,当这个通道发生异常事件时,需要及时在name server这边清理掉对应的broker信息。异常事件的类型有:(1)通道关闭时;(2)通道抛出异常时;(3)通道空闲时。
四、RouteInfoManager
这个模块是name server的核心模块,真正管理broker、消息队列等相关信息的地方。代码如下:
主要属性的含义如下:
BROKERCHANNELEXPIRED_TIME,表示一个broker距离上次发心跳包的最长时间,即120秒;
使用可重入读写锁实现并发安全、使用轻量级的非线程安全容器实现高效并发;【这点非常重要】
topicQueueTable:用于管理topic和属于这个topic的队列的映射关系;
brokerAddrTable:用于管理某个broker和它对应的信息
clusterAddrTable:用于管理broker集群和集群中对应的broker的映射关系
brokerLiveTable:用于管理broker的存活信息
filterServerTable:用于管理broker和过滤服务列表【暂不理解】
关于ReentrantReadWriteLock:
这里使用的锁是非公平锁
ReentrantReadWriteLock基于Sync、ReadLock、WriteLock三个模块实现,Sync负责处理公平与否的问题。ReadLock和WriteLock通过锁外部对象ReentrantReadWriteLock来处理并发。在RoutInfoManager中的使用案例如下:
五、KVConfigManager
这个模块用于管理name server自己的配置信息,配置信息以json信息存放在文件中,以二维数组形式存在于内存中,请看代码:
这个类对外暴露的方法有:
load方法:将配置信息加载到内存中
putKVConfig方法:将配置信息持久化
deleteKVConfig方法:删除指定的配置项
getKVListByNamespace和getKVConfig用于查询配置信息
参考资料
消息队列技术点梳理
netty的线程模型
《Java并发编程的艺术》
领取专属 10元无门槛券
私享最新 技术干货