数据路由
对于系统来说,要发送消息到MQ里去,还要从MQ里消费消息
那么大家怎么知道有哪些Broker?怎么知道要连接到哪一台Broker上去发送和接收消息?这是一个大问题!
所以RocketMQ为了解决这个问题,有一个
NameServer
的概念,他也是独立部署在几台机器上的,然后所有的Broker都会把自己注册到NameServer
上去,NameServer
不就知道集群里有哪些Broker了?然后对于我们的系统而言,如果他要发送消息到Broker,会找
NameServer
去获取路由信息,就是集群里有哪些Broker等信息如果系统要从Broker获取消息,也会找NameServer
获取路由信息,去找到对应的Broker获取消息。集群化部署
NameServer
是可以集群化部署的那为什么NameServer要集群化部署?最主要的一个原因,就是高可用性。
因为大家都知道,NameServer是集群里非常关键的一个角色,他要管理Broker信息,别人都要通过他才知道跟哪个Broker通信,所以没了他就会很麻烦!
那么如果
NameServer
就部署一台机器的话,一旦NameServer
宕机了,岂不是会导致RocketMQ
集群出现故障?所以通常来说,
NameServer
一定会多机器部署,实现一个集群,起到高可用的效果,保证任何一台机器宕机,其他机器上的NameServer
可以继续对外提供服务!Broker注册到NameServer的方式
每个Broker启动都得向所有的
NameServer
进行注册如果1台
NameServer
上有5个Broker的信息,另外1个NameServer
上有另外5个Broker的信息,那么此时任何一个NameServer
宕机了,不就导致5个Broker的信息就没了吗?所以这种做法是不靠谱的,会导致数据丢失,系统不可用。每个
NameServer
都会有一份集群中所有Broker的信息。
在这个图里就示范了一个
Master Broker
得向两台NameServer
都进行注册的情况,这才是真正的情况。系统从NameServer获取Broker信息的方式
扮演生产者和消费者的系统们,如何从NameServer那儿获取到集群的Broker信息呢?他们需要知道集群里有哪些Broker,才能根据一定的算法挑选一个Broker去发送消息或者获取消息。
有两种办法:
- NameServer那儿会主动发送请求给所有的系统,告诉他们Broker信息
这种办法靠谱吗?明显不靠谱,因为NameServer怎么知道要推送Broker信息给哪些系统?未卜先知吗?
- 第二种办法是这样的,每个系统自己每隔一段时间,定时发送请求到NameServer去拉取最新的集群Broker信息。
这个办法是靠谱的,没有什么明显的缺陷,所以RocketMQ中的生产者和消费者就是这样,自己主动去NameServer拉取Broker信息,并缓存在本地。
假设这个NameServer集群整体都故障了,失去了这个NameServer集群之后,生产者消费者在缓存过期时间内还能进行消息的发送和获取
顺便在这里解释一下,图里的路由信息,大致可以理解为集群里的Broker信息以及其他相关的数据信息
通过这些路由信息,每个系统就知道发送消息或者获取消息去哪台Broker上去进行了,这起到一个把消息路由到一个Broker上的效果,所以一般我们把这种信息叫做路由信息。
如果Broker挂了,NameServer是怎么感知到的?
现在一个Broker启动之后向NameServer注册了,每个NameServer都知道集群里有这么一台Broker的存在了,然后各个系统从NameServer那儿也拉取到了Broker信息,也知道集群里有这么一台Broker
心跳检测机制
但是如果之后这台Broker挂了呢?
要解决这个问题,靠的是Broker跟NameServer之间的心跳机制:
Broker会每隔30s给所有的NameServer发送心跳,告诉每个NameServer自己目前还活着。
每次NameServer收到一个Broker的心跳,就可以更新一下他的最近一次心跳的时间
NameServer会每隔10s运行一个任务,去检查一下各个Broker的最近一次心跳时间,如果某个Broker超过120s都没发送心跳了,那么就认为这个Broker已经挂掉了。
Broker跟NameServer之间的通信
在RocketMQ的实现中,采用的是TCP长连接进行通信。也就是说,Broker会跟每个NameServer都建立一个TCP长连接,然后定时通过TCP长连接发送心跳请求过去
所以各个NameServer就是通过跟Broker建立好的长连接不断收到心跳包,然后定时检查Broker有没有120s都没发送心跳包,来判定集群里各个Broker到底挂掉了没有。
每个Broker在进行定时的心跳汇报给NameServer的时候,都会告诉NameServer自己当前的数据情况
Broker挂了,系统是怎么感知到的?
如果Broker挂掉了,那么作为生产者和消费者的系统是怎么感知到的呢?难道必须得NameServer发送请求给所有的系统通知他们吗?
这个是不现实的,之前已经说过了,NameServer去发送这个东西非常的不靠谱。
但是如果NameServer没有及时通知给那些系统,那么有没有可能出现这样一种情况,刚开始集群里有10个Broker,各个系统从NameServer那里得知,都以为有10个Broker。
结果此时突然挂了一个Broker,120s没发心跳给NameServer,NameServer是知道现在只有9个Broker了。
但是此时其他系统是不知道只有9个Broker的,还以为有10个Broker,此时可能某个系统就会发送消息到那个已经挂掉的Broker上去,此时是绝对不可能成功发送消息的
如果确实是那个情况,可以有两种解决办法。
首先,你可以考虑不发送消息到那台Broker,改成发到其他Broker上去。
其次,假设你必须要发送消息给那台Broker,那么他挂了,他的Slave机器是一个备份,可以继续使用,你是不是可以考虑等一会儿去跟他的Slave进行通信?
总之,这些都是思路,但是现在我们先知道,对于生产者而言,他是有一套容错机制的,即使一下子没感知到某个Broker挂了,他可以有别的方案去应对。
而且过一会儿,系统又会重新从NameServer拉取最新的路由信息了,此时就会知道有一个Broker已经宕机了。