RocketMQ源码分析我们主要从NameSrv、路由、生产者、消费者、消息存储等方面一点点分析,本章主要讲的是路由相关的源码分析。
一、路由元信息
NameSrv中存储了topic的路由信息,这样跟生产者、消费者交互的时候,为两者提供topic的路由信息,NameSrv还得存储路由信息,还得管理节点,包括路由的注册和路由的清除。
路由信息主要在RouteInfoManager类中,其中主要包括以下几个HashMap,用来存储不同的信息。
topicQueueTable:Topic消息队列路由信息,主要记录了该topic存储在哪些broker中,NameSrv收到消息时会根据该路由表进行负载均衡。
brokerAddrTable:broker基础路由信息,主要包含broker名称、集群名称等;
clusterAddrTable:broker集群的路由信息,只包含集群中broker的名字;
brokerLiveTable:broker状态的路由信息,包含每个broker最后一次发送心跳的时间等,broker每次发送心跳包到NameSrv,该信息就会被更新;
filterServerTable:broker上的消息过滤等路由信息。
二、路由的注册
路由的注册涉及两方面,一个是broker端进行路由注册的请求,一个是namesrv端对路由注册请求的处理。
1、broker端路由注册的请求
BrokerStartup的启动类:org.apache.rocketmq.broker.BrokerStartup。
BrokerStartup的main()方法中调用start(createBrokerController(args)),先创建BrokerController再调用BrokerController的start()方法。
createBrokerController包含了三个步骤:创建BrokerController、实例化BrokerController、销毁BrokerController。
1.1、BrokerController的创建、实例化、销毁
创建BrokerController跟创建NameSrvController差不多,都是创建配置文件读取类、根据配置参数不同,读取不同的配置文件。
BrokerConfig是Broker配置文件类,不多说。
跟NameSrvController不同的是这里多了一个NettyClientConfig配置类,主要是broker要接收生产者的消息,这时是netty的服务端,而又要跟namesrv发送心跳包,因此又是netty的客户端。
跟NameSrvController一样-c以后跟的是配置文件的路径,读取了以后用来填充配置文件类。
BrokerController的实例化,调用controller的initialize方法,里面实例化不细说了,后面其他模块会细说的。
BrokerController的销毁,还是一样,在jvm中注册钩子函数,当jvm退出的时候调用钩子函数的run方法对资源进行释放。
1.2、路由注册的请求
路由注册的请求其实还是调用BrokerController的start()方法。
通过BrokerController的start()方法,可以看到调用了BrokerController的registerBrokerAll()方法,将broker相关信息都注册到namesrv。至于下面的定时线程任务,可以看到延迟十秒,然后每三十秒重新向namesrv注册一下自己,其实也就是每三十秒发送一次心跳。
我们再仔细看registerBrokerAll()方法,registerBrokerAll()方法调用了doRegisterBrokerAll()方法
doRegisterBrokerAll()方法调用了brokerOuterAPI的registerBrokerAll()方法
然后发现registerBrokerAll()方法中用线程池去注册
然后发现注册方法中有一个oneway的发送方式,就是直接发送心跳包,没有反馈的,默认不使用这个模式的。然后还有一个调用remotingClient的invokeSync同步注册方法
remotingClient其实就是一个netty客户端的实例,通过netty跟namesrv通信。
2、namesrv处理路由注册的请求
处理路由注册的请求是namesrv端的工作,相信大家都能理解。处理该请求的类org.apache.rocketmq.namesrv.processor下的DefaultRequestProcessor类中。处理方法是DefaultRequestProcessor的processRequest()方法。该方法中拿到请求code以后,通过code进行判断请求是什么请求。
其实调用的就是RouteInfoManager的registerBroker()方法
在registerBroker()方法中就能看到往brokerAddrTable、clusterAddrTable、brokerLiveTable中添加数据。这几个hashmap,是不是很熟悉,咱们介绍路由元信息的时候,是不是介绍过这几个,这几个存储的就是broker的路由元信息。
到此,路由的注册以及对应的处理都清楚了吧。broker通过netty的客户端发送路由的信息心跳包到namesrv,namesrv收到信息以后解析然后存储。
三、路由的删除
路由的删除包括两方面,一个是NamesrvController实例化的时候启动了一个定时线程任务扫描最近一次上报时间与当前时间相差两分钟以及以上的broker,然后删除。另一个是broker关闭的时候自动向namesrv发送删除路由信息的请求。
一个是NamesrvController中initialize()中使用线程扫描,然后最后一次上报时间到现在大于两分钟的,清除其路由相关的信息,
topicQueueTable、brokerAddrTable、clusterAddrTable、brokerLiveTable、filterServerTable等。
另一个是broker端BrokerStartup的shutdown()方法,就是用netty给namesrv发送了一个UNREGISTER_BROKER请求,然后namesrv收到以后进行处理,这里就不细说了,处理跟上面一样。都是移除路由相关的那几个hashmap里的信息,可以自己看一下。
四、路由的发现
路由的发现,其实就是namesrv上的路由信息发生了改变,但是不会主动去将变动推送给Producer,而是客服端主动去向namesrv发送请求,主动拉取路由相关信息,因此路由发现不是实时的。
在org.apache.rocketmq.namesrv.processor下的DefaultRequestProcessor中有对获取topic路由请求的处理。