深入浅出消息队列----【Broker 集群】
- 单 master
- 多 master
- 多 master 多 slave 异步复制
- 多 master 多 slave 同步复制
- Dledger
本文仅是文章笔记,整理了原文章中重要的知识点、记录了个人的看法
文章来源:编程导航-鱼皮【yes哥深入浅出消息队列专栏】
Broker cluster 可以分为五类:
- 单 master
- 多 master
- 多 master 多 slave 异步复制
- 多 master 多 slave 同步复制
- Dledger
单 master
如果我们仅部署了一个 Broker 实例,那么就是单 master 模式。
假设这个 master 宕机了,那么生产者发送消息会失败、消费者拉取消息也会失败。
此时整个消息队列就不可用了,影响了线上服务的正常执行。
基本上生产环境不会采取单 master 模式,这种一般只会在测试时候使用。
多 master
如果仅部署一个实例风险太大,那么部署两个就能避免 Broker 单点的风险。
此时两个 Broker 会互相瓜分对应的 Topic 下的队列,比如 TopicA 一共分了 8 哥队列,那么 Broker-1 承担其中的 4 哥,Broker-2 承担另外四个。
这样一来,生产者给不同队列发送消息,写入消息的压力已经均匀的分配到两个 Broker 身上了,提升了写消息的性能。
如果此时 Broker-1 宕机了,咋办呢?
生产者发送给 Broker-1 的消息会失败,但是还记得之前说过的同步、异步发送消息,如果发送失败,生产者会默认重试的机制吗?
没错,生产者会重试发送消息,而且此时会自动避让上次发送失败的 Broker,因此发给 Broker-1 失败后,会避让 Broker-1,会选择投递到 Broker-2,所以 Broker-1 宕机不会影响消息的发送。
但对于消费者而言,如果想消费队列-1到队列-4的消息,只能从 Broker-1 拉取,此时拉取肯定是失败的,因此**会影响宕机钱已经发送存储至 Broker-1 但还未被消费的消息,**这些消息的实时性无法保证,只能等 Broker-1 恢复。
不会影响新消息的消费,因为新的消息只会被发往 Broker-2。
这时候,只要 Broker-1 重启,那么消费者就能顺利地拉取之前在 Broker-1 的消息了(如果消息已经被刷盘了的话)。
什么叫刷盘呢?消息发送成功了,不代表一定已经被 Broker 持久化了
一般为了性能,消息写入到 Broker 后,还在页缓存中,不会同步刷到磁盘内,也就是消息写到页缓存就返回消息写入成功,此时如果断电了,那么在页缓存内的数据就没了,消息也就丢了。
如果想消息一定不丢,只能是同步刷盘,也就是每次消息写入都直接刷盘,这样消息是不会丢的,但是这样性能不好,这就要根据实际场景进行取舍了。
这里需要提一下,上述对生产者发送消息没有影响指的是普通消息,如果是顺序消息则会有影响。
因为顺序消息的实现是选择 Topic 下的某一队列进行发送,如果 Broker-1 宕机,本来都需要发送给队列-1 的消息,此时发送到队列-6,那么队列-1 的消息会宕机了还未被消费,队列-6 后来到的消息反而被消费了,此时消息的顺序性就无法保证了。
多 master 多 slave 异步复制
上述多 master 的模式,如果发生一个实例宕机会影响部分消息的实时性,因此就弄了哥 slave 来作为 master 的 backup。
每个 master 对应有一个 slave,正常情况下 slave 只会默默同步 master 的消息,不支持消息的直接写入,正常也不会对外提供消费。
只有当 master 繁忙(例如当拉取的消息太久远了或因为消息堆积严重,消息不在 master 内存中,就会返回繁忙,此时消费者就会去 slave 拉取消息,前提是 slaveReadEnable 参数要设置为 true),或者 master 挂了才会被消费者消费。
总而言之,当 master 不太行的时候,消费者可以选择对应的 slave 拉取消息,这样就避免了 master 不行后消息的实时性问题。
所以 slave 就是个备胎,当 master 不好了,消费者才会来找 slave。
那何为异步复制呢?
生产者将消息写到 master 后就返回成功了,然后 slave 回去 master 同步消息,也因此 slave 上的消息相对于 master 会有一定的滞后性,所以当 master 宕机,消费者从 slave 拉取消息的时候,可能会存在个别消息丢失的情况。
看到这可能有同学会有疑惑:为啥 slave 不能被生产者主动写入消息呐?
理论上是可以的,master 和 slave 都支持写入,但这需要实现 master 和 slave 之间数据的双向同步,互相同步消息保证消息的一致性,但这样会比较麻烦,会牵扯一些冲突,比如消息的顺序冲突等等。
多 master 多 slave 同步复制
如果想要保证 slave 的消息不丢失,那么可以采取同步复制的情况。
所谓同步复制其指的是生产者只有在消息存储到 master 以及对应的 slave 中后,才会得到消息写入成功的结果,这样就保证 slave 不会落后于 master。
也因此,在同步复制的情况下,当 master 挂了,消费者从 slave 拉取到的事完整的消息。
当然,这样消息是可靠了,但是对性能会有一定的损耗,因为本来生产者仅需等消息写到 master 就直接返回了,现在还得多等一下,等 slave 也写完了才能返回。
不过这种模式还是无法解决消息写入的问题,即 master 宕机后,消息写入的压力无法被 slave 分担到。
Dledger
Dledger 集群算是 RocketMQ 集群的终极版本了。
Dledger 集群指的是一组具有相同名称的 Broker,至少有 3 哥节点,它们组成 RocketMQ-on-Dledger Group,这个集群基于 raft 协议(一致性协议),实现自动的主从切换。
当主节点挂了,那么集群内会自动选举出新的主节点。
按照 raft 协议的术语,主节点就是 leader,想要组成这个集群,至少需要三台机子,也就是至少还得有 2 哥 follower,这样根据投票的规则,当 leader 挂了,才能自动从 follower 中选出新的 leader,此时就自动完成了主从切换,使得消息能正常的写入。
之前的集群模式,当 master 挂了之后,slave 还是 slave,无法自动被提升为 master,而 Dledger 则可以自动完成主从切换,非常顺滑。
之所以可以自动从 follower 中投票选取出 leader 是因为 Dledger 会接管 commitlog 的存储,通过 raft 协议,follower 会同步 leader 的 commitlog,保证消息的一致性。
可以简单理解集群中的消息存储都是一致性的,不会出现消息顺序不一致等数据冲突等问题,因此当 leader 没了,可以从 follower 中选一个提升为 leader,反正消息都是对的。
这个模式的缺点就是需要多点机器才能实现 Dledger 集群,等于以前是一个 master 配备一共 slave,现在是一个 leader 至少配备两个 follower。