RocketMQ升级Dledger⾼可⽤集群

198 阅读9分钟

主从架构的RocketMQ集群,由于给每个broker服务配置了⼀个或多个slave备份服务,可以保证当broker服务 出现问题时,broker上的消息不会丢失。但是,这种主从架构的集群却也有⼀个不⾜的地⽅,那就是不具备服 务⾼可⽤。

这⾥所说的服务⾼可⽤,并不是并不是指整个RocketMQ集群就不能对外提供服务了,⽽是指集群中的消息就不完整了。实际上,当RocketMQ集群中的broker宕机后,整个集群会⾃动进⾏broker状态感知。后续客户端的各种请求,依然可以转发到其他正常的broker上。只不过,原本保存在当前broker上的消息,就无法正常读取了,需要等到当前broker服务重启后,才能重新被消息消费者读取。

当⼀个broker上的服务宕机后,我们可以从对应的slave服务上找到broker上所有的消息。但是很可惜,主从架构中各个服务的⻆⾊都是固定了的,slave服务虽然拥有全部的数据,但是它没办法升级成为master服务去响应客户端的请求,依然只是傻傻等待master服务重启后,继续做它的数据备份⼯作。

这时,我们⾃然就希望这个slave服务可以升级成为master服务,继续响应客户端的各种请求,这样整个集群的消息服务就不会有任何中断。⽽RocketMQ提供的Dledger集群,就是具备⻆⾊⾃动转换功能的⾼可⽤集群。

整个集群结构如下图所示:

图片.png

在Dledger集群中,就不再单独指定各个broker的服务,⽽是由这些broker服务⾃⾏进⾏选举,产⽣⼀个Leader⻆⾊的服务,响应客户端的各种请求。⽽其他的broker服务,就作为Follower⻆⾊,负责对Leader上的数据进行备份。当然,Follower所要负责的事情,⽐主从架构中的SLAVE⻆⾊会要复杂⼀点,因为这种节点选举是在后端不断进⾏的,他们需要随时做好升级成Leader的准备。

Dledger集群的选举是通过Raft协议进行的,Raft协议是⼀种多数同意机制。也就是每次选举需要有集群中超 过半数的节点确认,才能形成整个集群的共同决定。同时,这也意味着在Dledger集群中,只要有超过半数的 节点能够正常⼯作,那么整个集群就能正常⼯作。因此,在部署Dledger集群时,通常都是部署奇数台服务, 这样可以让集群的容错性达到最⼤。

接下来,我们就⽤之前准备的3台服务器,搭建⼀个3个节点的Dledger集群。在这个集群中,只需要有2台Broker服务正常运⾏,这个集群就能正常⼯作。

第⼀步:部署nameserver

这⼀步和之前部署主从集群没有区别,不需要做过多的配置,直接在三台服务器上启动nameserver服务即可。

实际上,如果你是从上⼀个主从架构开始搭建起来的话,那么nameserver集群都不需要重新启动,nameserver会⾃动感知到broker的变化。

第⼆步:对Broker服务进行集群配置。

对于Dledger集群的配置,RocketMQ依然贴⼼的给出了完整的示例,不需要强⾏记忆。

在conf/dledger⽬录下,RocketMQ默认给出了三个配置⽂件,这三个配置⽂件可以在单机情况下直接部署成⼀个具有三个broker服务的Dledger集群,我们只需要按照这个配置进⾏修改即可。

接下来我们可以在三台机器的conf/dledger⽬录下,都创建⼀个broker.conf⽂件,对每个broker服务进⾏配置。

worker1的broker.conf配置示例

brokerClusterName = RaftCluster
brokerName=RaftNode00
listenPort=30911
namesrvAddr=worker1:9876;worker2:9876;worker3:9876
storePathRootDir=/app/rocketmq/storeDledger/
storePathCommitLog=/app/rocketmq/storeDledger/commitlog
storePathConsumeQueue=/app/rocketmq/storeDledger/consumequeue
storePathIndex=/app/rocketmq/storeDledger/index
storeCheckpoint=/app/rocketmq/storeDledger/checkpoint
abortFile=/app/rocketmq/storeDledger/abort
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
dLegerPeers=n0-worker1:40911;n1-worker2:40911;n2-worker3:40911
## must be unique
dLegerSelfId=n0
sendMessageThreadPoolNums=16

worker2的broker.conf配置示例:

brokerClusterName = RaftCluster
brokerName=RaftNode00
listenPort=30911
namesrvAddr=worker1:9876;worker2:9876;worker3:9876
storePathRootDir=/app/rocketmq/storeDledger/
storePathCommitLog=/app/rocketmq/storeDledger/commitlog
storePathConsumeQueue=/app/rocketmq/storeDledger/consumequeue
storePathIndex=/app/rocketmq/storeDledger/index
storeCheckpoint=/app/rocketmq/storeDledger/checkpoint
abortFile=/app/rocketmq/storeDledger/abort
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
dLegerPeers=n0-worker1:40911;n1-worker2:40911;n2-worker3:40911
## must be unique
dLegerSelfId=n1
sendMessageThreadPoolNums=16

worker3的broker.conf配置示例:

brokerClusterName = RaftCluster
brokerName=RaftNode00
listenPort=30911
namesrvAddr=worker1:9876;worker2:9876;worker3:9876
storePathRootDir=/app/rocketmq/storeDledger/
storePathCommitLog=/app/rocketmq/storeDledger/commitlog
storePathConsumeQueue=/app/rocketmq/storeDledger/consumequeue
storePathIndex=/app/rocketmq/storeDledger/index
storeCheckpoint=/app/rocketmq/storeDledger/checkpoint
abortFile=/app/rocketmq/storeDledger/abort
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
dLegerPeers=n0-worker1:40911;n1-worker2:40911;n2-worker3:40911
## must be unique
dLegerSelfId=n2
sendMessageThreadPoolNums=16

这⾥对⼏个需要重点关注的配置项,做下介绍:

  • enableDLegerCommitLog: 是否启动Dledger。true表示启动
  • namesrvAddr: 指定nameserver地址
  • dLedgerGroup: Dledger Raft Group的名字,建议跟brokerName保持⼀致。
  • dLedgerPeers: Dledger Group内各个服务节点的地址及端⼝信息。同⼀个Group内的各个节点配置必须要保持⼀致。
  • dLedgerSelfId: Dledger节点ID,必须属于dLedgerPeers中的⼀个。同⼀个Group内的各个节点必须不能重复。
  • sendMessageThreadPoolNums:dLedger内部发送消息的线程数,建议配置成cpu核⼼数。
  • store开头的⼀系列配置: 这些是配置dLedger集群的消息存盘⽬录。如果你是从主从架构升级成为
  • dLedger架构,那么这个地址可以指向之前搭建住主从架构的地址。dLedger集群会兼容主从架构集群的消息格式,只不过主从架构的消息⽆法享受dLedger集群的两阶段同步功能。

第三步:启动broker服务

和启动主从架构的broker服务⼀样,我们只需要在启动broker服务时,指定配置⽂件即可。在三台服务器上分 别执⾏以下指令,启动broker服务。

cd /app/rocketmq/rocketmq-all-5.3.0-bin-release/
nohup bin/mqbroker -c conf/dledger/broker.conf &

第四步:检查集群服务状态

我们可以在Dashboard控制台的集群菜单⻚看到Dledger集群的运行状况。

图片.png

从整个配置过程中可以看到,我们并没有指定每个节点的⻆⾊,⽽Dledger集群就⾃动将192.168.232.129也 就是worker2上的broker服务选举成了master。

停⽌woker2上的broker服务,再重新观察集群的运⾏状况。RocketMQ 会在发现worker2服务宕机后,很快的选举产⽣新的master节点。但具体选举出worker1还是worker3作为 master,则是随机的。

如果继续停⽌worker1或worker3上的broker服务,那么集群中宕机的broker服务就超过了半 数,也就是两台。这时这个Dledger集群就选举不出master节点,也就⽆法正常⼯作了。

关于Dledger集群的⼀些补充

Dledger集群机制是RocketMQ⾃4.5版本开始⽀持的⼀个重要特性。他其实是由OpenMessage组织带⼊ RocketMQ的⼀个系列框架。他是⼀个为⾼可⽤、⾼性能、⾼可靠的分布式存储系统提供基础⽀持的组件。他 做的事情主要有两个,⼀是在集群中选举产⽣master节点。RocketMQ集群需要⽤这个master节点响应客户端 的各种请求。⼆是在各种复杂的分布式场景下,保证CommitLog⽇志⽂件在集群中的强⼀致性。

以下是ChatGPT对于Dledger的功能描述

图片.png

其背后的核心就是Raft协议。这是⼀种强⼤的分布式选举算法,其核心是只要集群中超过半数的节点作出的共 同决议,就认为是集群最终的共同决议。

Raft协议通过投票机制保持数据一致性。详细的细节,我们这⾥不做过多讨论,只是给你介绍⼀下Raft协议⼀ 个很强⼤的地⽅,就是他解决了分布式集群中的脑裂问题

关于脑裂问题,这是在集群选举过程中⼀个出现概率不⾼,但是让很多⼈头疼的问题。在分布式集群内,有可 能会由于⽹络波动或者其他⼀些不稳定因素,造成集群内节点之间短时间通信不畅通。这时就容易在集群内形 成多个包含多个节点的⼩集合。这些集合就会独⽴进⾏选举,各⾃产⽣新的Master节点。当⽹络恢复畅通后, 集群中就有了多个Master节点。当集群中出现多个Master节点后,其他节点就不知道要听从谁的指令了,从⽽ 造成集群整体⼯作瘫痪。也就是俗话说的“⼀⼭不容⼆⻁”。脑裂问题在以Zookeeper为代表的早前⼀代分布式 ⼀致性产品中,是⼀个⾮常头疼的问题。⽽Raft协议对于脑裂问题,会采⽤随机休眠的机制,彻底解决脑裂问 题。RocketMQ是Raft协议的⼀个重要的成功示例。Kafka也在之后基于Raft协议,⾃⾏实现了Kraft集群机制。

总结RocketMQ的运⾏架构

图片.png

接下来,我们就完整梳理一下RocketMQ中各个组件的作用:

1、nameServer 命名服务

在我们之前的实验过程中,你会发现,nameServer不依赖于任何其他的服务,⾃⼰独⽴就能启动。并且,不 管是broker还是客户端,都需要明确指定nameServer的服务地址。以⼀台电脑为例,nameServer可以理解为 是整个RocketMQ的CPU,整个RocketMQ集群都要在CPU的协调下才能正常⼯作。

2、broker 核⼼服务

从之前的实验过程中你会发现,broker是RocketMQ中最为娇贵的⼀个组件。RockeMQ提供了各种各样的重 要设计来保护broker的安全。同时broker也是RocketMQ中配置最为繁琐的部分。同样以电脑为例,broker就 是整个RocketMQ中的硬盘、显卡这⼀类的核心硬件。RocketMQ最核心的消息存储、传递、查询等功能都要 由broker提供。

3、client 客户端 Client包括消息⽣产者和消息消费者。同样以电脑为例,Client可以认为是RocketMQ中的键盘、⿏标、显示器 这类的输⼊输出设备。⿏标、键盘输⼊的数据需要传输到硬盘、显卡等硬件才能进⾏处理。但是键盘、⿏标是 不能直接将数据输⼊到硬盘、显卡的,这就需要CPU进⾏协调。通过CPU,⿏标、键盘就可以将输⼊的数据最 终传输到核⼼的硬件设备中。经过硬件设备处理完成后,再通过CPU协调,显示器这样的输出设备就能最终从 核⼼硬件设备中获取到输出的数据