RocketMQ5.0主备自动切换模式部署

主备自动切换模式部署

架构图

背景

当前 RocketMQ Raft 模式主要是利用 DLedger Commitlog 替换原来的 Commitlog,使 Commitlog 拥有选举复制能力,但这也造成了一些问题:

  • Raft 模式下,Broker组内副本数必须是三副本及以上,副本的ACK也必须遵循多数派协议。
  • RocketMQ 存在两套 HA 复制流程,且 Raft 模式下的复制无法利用 RocketMQ 原生的存储能力。

因此我们希望利用 DLedger 实现一个基于 Raft 的一致性模块(DLedger Controller),并当作一个可选的选主组件,支持独立部署,也可以嵌入在 Nameserver 中,Broker 通过与 Controller 的交互完成 Master 的选举,从而解决上述问题,我们将该新模式称为 Controller 模式。

架构

核心思想

架构图

如图是 Controller 模式的核心架构,介绍如下:

  • DledgerController:利⽤ DLedger ,构建⼀个保证元数据强⼀致性的 DLedger Controller 控制器,利⽤ Raft 选举会选出⼀个 Active DLedger Controller 作为主控制器,DLedger Controller 可以内嵌在 Nameserver中,也可以独立的部署。其主要作用是,用来存储和管理 Broker 的 SyncStateSet 列表,并在某个 Broker 的 Master Broker 下线或⽹络隔离时,主动发出调度指令来切换 Broker 的 Master。
  • SyncStateSet:主要表示⼀个 broker 副本组中跟上 Master 的 Slave 副本加上 Master 的集合。主要判断标准是 Master 和 Slave 之间的差距。当 Master 下线时,我们会从 SyncStateSet 列表中选出新的 Master。 SyncStateSet 列表的变更主要由 Master Broker 发起。Master通过定时任务判断和同步过程中完成 SyncStateSet 的Shrink 和 Expand,并向选举组件 Controller 发起 Alter SyncStateSet 请求。
  • AutoSwitchHAService:一个新的 HAService,在 DefaultHAService 的基础上,支持 BrokerRole 的切换,支持 Master 和 Slave 之间互相转换 (在 Controller 的控制下) 。此外,该 HAService 统一了日志复制流程,会在 HA HandShake 阶段进行日志的截断。
  • ReplicasManager:作为一个中间组件,起到承上启下的作用。对上,可以定期同步来自 Controller 的控制指令,对下,可以定期监控 HAService 的状态,并在合适的时间修改 SyncStateSet。ReplicasManager 会定期同步 Controller 中关于该 Broker 的元数据,当 Controller 选举出一个新的 Master 的时候,ReplicasManager 能够感知到元数据的变化,并进行 BrokerRole 的切换。

DLedgerController 核心设计

image-20220605213143645

如图是 DledgerController 的核心设计:

  • DLedgerController 可以内嵌在 Namesrv 中,也可以独立的部署。
  • Active DLedgerController 是 DLedger 选举出来的 Leader,其会接受来自客户端的事件请求,并通过 DLedger 发起共识,最后应用到内存元数据状态机中。
  • Not Active DLedgerController,也即 Follower 角色,其会通过 DLedger 复制来自 Active DLedgerController 的事件日志,然后直接运用到状态机中。

构建集群环境准备

该集群至少三台服务器
服务器说明:(生产中应该将 NameServer 部署到其他服务器中,在这为了方便,与Broker部署在一起)
服务器角色
IP地址
安装的服务
服务器1
192.168.0.73
DLedger,Broker,NameServer
服务器2
192.168.0.74
DLedger,Broker,NameServer
服务器3
192.168.0.75
DLedger,Broker,NameServer

Controller 部署

Controller 部署有两种方式。一种是嵌入于 NameServer 进行部署,可以通过配置 enableControllerInNamesrv 打开(可以选择性打开,并不强制要求每一台 NameServer 都打开),在该模式下,NameServer 本身能力仍然是无状态的,也就是内嵌模式下若 NameServer 挂掉多数派,只影响切换能力,不影响原来路由获取等功能。另一种是独立部署,需要单独部署 Controller 组件。

Controller 嵌入 NameServer 部署

 内嵌部署图

安装Java环境

yum install -y java-1.8.0-openjdk java-devel

下载RocketMQ5.0

wget https://dlcdn.apache.org/rocketmq/5.0.0/rocketmq-all-5.0.0-bin-release.zip
下载完成后解压到本地
unzip rocketmq-all-5.0.0-bin-release.zip
创建数据存储目录:
cd rocketmq-all-5.0.0-bin-release
mkdir -p rmqstore/commitlog rmqstore/consumequeue rmqstore/index
  • commitlog:生产者投递到rocketmq的数据所存储的目录
  • consumequeue:存储offset数据,用于对commitlog的数据进行索引
  • index:随机读时用到的索引文件
修改日志配置文件:
mkdir logs
sed -i 's#${user.home}#/opt/rocketmq#g' conf/*.xml

嵌入 NameServer 部署时只需要在 NameServer 的配置文件中设置 enableControllerInNamesrv=true,并填上 Controller 的配置即可。

服务器1配置

# 文件名 conf/controller/cluster-3n-namesrv-plugin/namesrv-n0.conf
#Namesrv config
listenPort = 9876
enableControllerInNamesrv = true

#controller config
controllerDLegerGroup = group1
controllerDLegerPeers = n0-192.168.0.73:9878;n1-192.168.0.74:9878;n2-192.168.0.75:9878
controllerDLegerSelfId = n0
controllerStorePath = /data/rocketmq/rmqstore/DledgerController

服务器2配置

# 文件名 conf/controller/cluster-3n-namesrv-plugin/namesrv-n1.conf
#Namesrv config
listenPort = 9876
enableControllerInNamesrv = true

#controller config
controllerDLegerGroup = group1
controllerDLegerPeers = n0-192.168.0.73:9878;n1-192.168.0.74:9878;n2-192.168.0.75:9878
controllerDLegerSelfId = n1
controllerStorePath = /data/rocketmq/rmqstore/DledgerController

服务器3配置

# 文件名 conf/controller/cluster-3n-namesrv-plugin/namesrv-n2.conf
#Namesrv config
listenPort = 9876
enableControllerInNamesrv = true

#controller config
controllerDLegerGroup = group1
controllerDLegerPeers = n0-192.168.0.73:9878;n1-192.168.0.74:9878;n2-192.168.0.75:9878
controllerDLegerSelfId = n2
controllerStorePath = /data/rocketmq/rmqstore/DledgerController

参数解释:

  • enableControllerInNamesrv:Nameserver 中是否开启 controller,默认 false。
  • controllerDLegerGroup:DLedger Raft Group 的名字,同一个 DLedger Raft Group 保持一致即可。
  • controllerDLegerPeers:DLedger Group 内各节点的端口信息,同一个 Group 内的各个节点配置必须要保证一致。
  • controllerDLegerSelfId:节点 id,必须属于 controllerDLegerPeers 中的一个;同 Group 内各个节点要唯一。
  • controllerStorePath:controller 日志存储位置。controller 是有状态的,controller 重启或宕机需要依靠日志来恢复数据,该目录非常重要,不可以轻易删除。
  • enableElectUncleanMaster:是否可以从 SyncStateSet 以外选举 Master,若为 true,可能会选取数据落后的副本作为 Master 而丢失消息,默认为 false。
  • notifyBrokerRoleChanged:当 Broker 副本组上角色发生变化时是否主动通知,默认为 true。

参数设置完成后,指定配置文件启动 Nameserver 即可。

nohup sh mqnamesrv -c /opt/rocketmq/conf/controller/cluster-3n-namesrv-plugin/namesrv-n0.conf >/dev/null 2>&1 &
nohup sh mqnamesrv -c /opt/rocketmq/conf/controller/cluster-3n-namesrv-plugin/namesrv-n1.conf >/dev/null 2>&1 &
nohup sh mqnamesrv -c /opt/rocketmq/conf/controller/cluster-3n-namesrv-plugin/namesrv-n2.conf >/dev/null 2>&1 &

Broker 部署

文件位置 conf/dledger/broker-n0.conf

服务器1配置

## 集群名
brokerClusterName = Salary-RaftCluster
## broker组名,同一个RaftClusterGroup内,brokerName名要一样
brokerName=RaftNode00
## 监听的端口
listenPort=30911
## 你设置的NameServer地址和端口
namesrvAddr=192.168.0.73:9876;192.168.0.74:9876;192.168.0.75:9876
storePathRootDir=/opt/rocketmq/rmqstore/node00
storePathCommitLog=/opt/rocketmq/rmqstore/node00/commitlog
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
## n0 n1 n2 分别是broker1,broker2,broker3 的 dLegerSelfId
## 例如:dLegerPeers=n0-服务器1的IP:40911;n1-服务器2的IP:40912;n2-服务器3的IP:40913
dLegerPeers=n0-192.168.0.73:40911;n1-192.168.0.74:40912;n2-192.168.0.75:40913
## must be unique
## 这个值必须是在同一个RaftClusterGroup内唯一的
dLegerSelfId=n0
sendMessageThreadPoolNums=16
## 由于我的虚拟机配置了多个网卡,所以会绑定ip错误,因此我配置了这项,
brokerIP1=192.168.0.73

服务器2配置

## 集群名
brokerClusterName = Salary-RaftCluster
## broker组名,同一个RaftClusterGroup内,brokerName名要一样
brokerName=RaftNode00
## 监听的端口
listenPort=30911
## 你设置的NameServer地址和端口
namesrvAddr=192.168.0.73:9876;192.168.0.74:9876;192.168.0.75:9876
storePathRootDir=/opt/rocketmq/rmqstore/node01
storePathCommitLog=/opt/rocketmq/rmqstore/node01/commitlog
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
## n0 n1 n2 分别是broker1,broker2,broker3 的 dLegerSelfId
## 例如:dLegerPeers=n0-服务器1的IP:40911;n1-服务器2的IP:40912;n2-服务器3的IP:40913
dLegerPeers=n0-192.168.0.73:40911;n1-192.168.0.74:40912;n2-192.168.0.75:40913
## must be unique
## 这个值必须是在同一个RaftClusterGroup内唯一的
dLegerSelfId=n1
sendMessageThreadPoolNums=16
## 由于我的虚拟机配置了多个网卡,所以会绑定ip错误,因此我配置了这项,
brokerIP1=192.168.0.74

服务器3配置

## 集群名
brokerClusterName = Salary-RaftCluster
## broker组名,同一个RaftClusterGroup内,brokerName名要一样
brokerName=RaftNode00
## 监听的端口
listenPort=30911
## 你设置的NameServer地址和端口
namesrvAddr=192.168.0.73:9876;192.168.0.74:9876;192.168.0.75:9876
storePathRootDir=/opt/rocketmq/rmqstore/node02
storePathCommitLog=/opt/rocketmq/rmqstore/node02/commitlog
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
## n0 n1 n2 分别是broker1,broker2,broker3 的 dLegerSelfId
## 例如:dLegerPeers=n0-服务器1的IP:40911;n1-服务器2的IP:40912;n2-服务器3的IP:40913
dLegerPeers=n0-192.168.0.73:40911;n1-192.168.0.74:40912;n2-192.168.0.75:40913
## must be unique
## 这个值必须是在同一个RaftClusterGroup内唯一的
dLegerSelfId=n2
sendMessageThreadPoolNums=16
## 由于我的虚拟机配置了多个网卡,所以会绑定ip错误,因此我配置了这项,
brokerIP1=192.168.0.75
配置完成启动broker
nohup sh mqbroker -c /opt/rocketmq/conf/dledger/broker-n0.conf >/dev/null 2>&1 &
nohup sh mqbroker -c /opt/rocketmq/conf/dledger/broker-n1.conf >/dev/null 2>&1 &
nohup sh mqbroker -c /opt/rocketmq/conf/dledger/broker-n2.conf >/dev/null 2>&1 &

部署rocketmq- dashboard

docker run -d --name rocketmq-dashboard -e "JAVA_OPTS=-Drocketmq.namesrv.addr=192.168.0.73:9876;192.168.0.74:9876;192.168.0.75:9876" -p 8080:8080 -t apacherocketmq/rocketmq-dashboard:latest

 dashboard地址:IP:8080

四、工具测试消息收发

在进行工具测试消息收发之前,我们需要告诉客户端NameServer的地址,RocketMQ有多种方式在客户端中设置NameServer地址,这里我们利用环境变量NAMESRV_ADDR
$ export NAMESRV_ADDR=localhost:9876 
$ sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer 
SendResult [sendStatus=SEND_OK, msgId= ... 

$ sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer 
ConsumeMessageThread_%d Receive New Messages: [MessageExt...

参考文档:
https://github.com/apache/rocketmq/blob/develop/docs/cn/controller/design.md
https://rocketmq.apache.org/zh/docs/deploymentOperations/03autofailover/#controller-%E9%83%A8%E7%BD%B2
https://rocketmq.apache.org/zh/docs/4.x/bestPractice/02dledger/
1
如无特殊说明,文章均为本站原创,转载请注明出处

该文章由 发布

这货来去如风,什么鬼都没留下!!!
发表我的评论

Hi,请填写昵称和邮箱!

取消评论
代码 贴图 加粗 链接 删除线 签到
(2)条精彩评论:
  1. mango
    5.x不需要部署proxy模块吗?
    mango2023-06-13 16:13 回复
    • John
      需要
      John2024-01-22 17:40 回复