集群搭建
基于NameServer,RocketMQ搭建集群比较简单,通过少许配置即可完成
RocketMQ对于搭建集群给出了示例配置,在安装目录就可以看到

- 2m-2s-async:普通集群,二主二从,异步复制
- 2m-2s-sync:普通集群,二主二从,同步复制
- 2m-noslave:普通集群,二主无从,异步复制,不过实际文件夹中多了一个broker-trace
- container:container集群,二主二从,同步复制,RocketMQ 5.0 引入了 BrokerContainer 的概念,一个 BrokerContainer 中可以部署多个 Broker,这些 Broker 拥有独立的端口,功能完全独立,可以通过 admin 来增加或减少 Broker
- controller:controller集群,文件夹中主要包含了controller组件集群搭建,为了dledger模式存在的问题,RocketMQ 5.0以后推出了Controller模式
- dledger:dledger集群,为了解决普通集群无法主备切换的问题,文件夹中给出了三个节点的示例,可以理解为一主二从
普通集群
这里以二主二从的同步复制举例
配置
需要注意,逻辑上来讲,主节点和对应的从节点构成的是一个Broker,对于客户端或者服务端来说,是集群中的一个Broker
1 2 3 4 5 6 7 8 9 10
| brokerClusterName=DefaultCluster #集群名称 brokerName=broker-a #节点名称,主从节点的节点名称相同,以确定主从关系 brokerId=0 #节点id,0表示主节点 大于0表示从节点,需要和brokerRole对应 namesrvAddr=127.0.0.1:9876 #NameServer地址 deleteWhen=04 #磁盘文件空间充足情况下,默认每天什么时候执行删除过期文件,默认04表示凌晨4点 fileReservedTime=48 #文件保留时间,默认72小时,表示非当前写文件最后一次更新时间加上filereservedtime小于当前时间,该文件将被清理 brokerRole=SYNC_MASTER #节点角色,SYNC_MASTER,代表为主节点,并且为同步复制 flushDiskType=ASYNC_FLUSH #刷盘策略,ASYNC_FLUSH为异步刷盘 storePathRootDir=D:/store-a #持久化目录,如果是同一台机器部署测试,每个节点都需要配置一个目录 listenPort=10110 #监听端口,如果是同一台机器部署测试,各节点的端口需要间隔大一点,因为rocketmq同时会占用相邻的几个节点
|
1 2 3 4 5 6 7 8 9 10
| brokerClusterName=DefaultCluster #集群名称 brokerName=broker-a #节点名称,主从节点的节点名称相同,以确定主从关系 brokerId=1 #节点id,0表示主节点 大于0表示从节点,需要和brokerRole对应 namesrvAddr=127.0.0.1:9876 #NameServer地址 deleteWhen=04 #磁盘文件空间充足情况下,默认每天什么时候执行删除过期文件,默认04表示凌晨4点 fileReservedTime=48 #文件保留时间,默认72小时,表示非当前写文件最后一次更新时间加上filereservedtime小于当前时间,该文件将被清理 brokerRole=SLAVE #节点角色,SLAVE为从节点 flushDiskType=ASYNC_FLUSH #刷盘策略,ASYNC_FLUSH为异步刷盘 storePathRootDir=D:/store-a-s #持久化目录,如果是同一台机器部署测试,每个节点都需要配置一个目录 listenPort=10210 #监听端口,如果是同一台机器部署测试,各节点的端口需要间隔大一点,因为rocketmq同时会占用相邻的几个节点
|
集群b和集群a配置类似,只有节点名称不相同,另外单机测试部署的话,storePathRootDir和listenPort两个配置也需要注意
有了配置文件之后,使用命令mqbroker.cmd -c <对应的配置文件>分别启动对应节点即可,部署完通过dashboard查看,可以看到以下内容

特点
- 消息处理:
- 支持负载均衡,写入消息时,会负载到不同的broker,一条消息可能写入broker-a,也可能写入broker-b,这样可以减轻每个节点的压力,并且支持水平扩展
- 只有主节点可以处理写入请求,写入主节点后,再同步给从节点
- 从节点支持处理读取请求,但是有限制,需要slaveReadEnable配置为true,并且未读取的消息超过RocketMQ可以占用物理内存(受accessMessageInMemoryMaxRatio参数控制)时(此时因为内存放不下,会需要读取硬盘,影响性能),会从从节点读取
- 高可用性限制:
- 普通集群不支持故障转移,如果主节点挂掉了,从节点无法升级主节点,该Broker无法继续提供服务,对于整个rocketmq集群来说会丢失部分消息,并且会加大其他borker的压力
dledger集群
官方参考文档:https://rocketmq.apache.org/zh/docs/bestPractice/02dledger
dledger集群和普通集群的区别是故障转移,由于dledger集群采用raft算法,对于节点数量有要求,结构上只有这一点区别,其余结构是一样的。持久化方面,由于引入raft算法,commitlog日志和rocketmq原本的文件结构是不一样的
配置
由于dledger集群采用raft算法选主,所以不需要brokerId和flushDiskType等涉及角色的配置
1 2 3 4 5 6 7 8 9 10
| brokerClusterName = RaftCluster #集群名称 brokerName=RaftNode00 #节点名称,参考普通集群 namesrvAddr=127.0.0.1:9876 #NameServer地址 enableDLegerCommitLog=true #是否启动 DLedger dLegerGroup=RaftNode00 #DLedger Raft Group的名字,建议和 brokerName 保持一致 dLegerSelfId=n0 #节点id, 必须属于dLegerPeers中的一个,同 Group 内各个节点要唯一 sendMessageThreadPoolNums=16 #发送线程个数,建议配置成 Cpu 核数 dLegerPeers=n0-127.0.0.1:40911;n1-127.0.0.1:40912;n2-127.0.0.1:40913 #DLedger Group 内各节点的端口信息,同一个 Group 内的各个节点配置必须要保证一致 listenPort=10110 #监听端口号 storePathRootDir=D:\store-n0 #持久化目录
|
1 2 3 4 5 6 7 8 9 10
| brokerClusterName = RaftCluster #集群名称 brokerName=RaftNode00 #节点名称,参考普通集群 namesrvAddr=127.0.0.1:9876 #NameServer地址 enableDLegerCommitLog=true #是否启动 DLedger dLegerGroup=RaftNode00 #DLedger Raft Group的名字,建议和 brokerName 保持一致 dLegerSelfId=n1 #节点id, 必须属于dLegerPeers中的一个,同 Group 内各个节点要唯一 sendMessageThreadPoolNums=16 #发送线程个数,建议配置成 Cpu 核数 dLegerPeers=n0-127.0.0.1:40911;n1-127.0.0.1:40912;n2-127.0.0.1:40913 #DLedger Group 内各节点的端口信息,同一个 Group 内的各个节点配置必须要保证一致 listenPort=10210 #监听端口号 storePathRootDir=D:\store-n1 #持久化目录
|
1 2 3 4 5 6 7 8 9 10
| brokerClusterName = RaftCluster #集群名称 brokerName=RaftNode00 #节点名称,参考普通集群 namesrvAddr=127.0.0.1:9876 #NameServer地址 enableDLegerCommitLog=true #是否启动 DLedger dLegerGroup=RaftNode00 #DLedger Raft Group的名字,建议和 brokerName 保持一致 dLegerSelfId=n1 #节点id, 必须属于dLegerPeers中的一个,同 Group 内各个节点要唯一 sendMessageThreadPoolNums=16 #发送线程个数,建议配置成 Cpu 核数 dLegerPeers=n0-127.0.0.1:40911;n1-127.0.0.1:40912;n2-127.0.0.1:40913 #DLedger Group 内各节点的端口信息,同一个 Group 内的各个节点配置必须要保证一致 listenPort=10210 #监听端口号 storePathRootDir=D:\store-n1 #持久化目录
|
除了选主方面以及dLeger特有的配置,其余配置都一样。这里的举例是三个节点构成一个broker,但是dLeger仍然支持多个broker,这一点和普通集群是一样的
有了配置文件之后,使用命令mqbroker.cmd -c <对应的配置文件>分别启动对应节点即可,部署完通过dashboard查看,可以看到以下内容

特点
- 消息复制
- 在消息处理方面,dledger集群和普通集群是一致的,支持多broker负载均衡,以及水平扩展,在读、写请求方面也是一致的,但是dledger模式下,持久化文件发生了变化,比普通集群更加复杂
- 高可用性
- dledger集群支持故障转移,主节点掉线后,通过raft算法从从节点中选出一个升为主节点
- 数量限制
- 由于采用raft算法,dledger集群下一个broker起码有三个节点才能实现故障转移,即起码三节点才能接受主节点下线
- 节点复制
- 由于采用raft算法,基于多数派协议,主节点收到消息后,将消息复制给从节点并且需要收到半数以上的从节点的回复才能返回确认给客户端,相当于一种折中的同步复制,并且是强制的
controller集群
官方参考文档:https://github.com/apache/rocketmq/tree/develop/docs/cn/controller
controller集群的出现是为了解决dledger集群的问题,以下是官网的介绍


这里之所以叫它为controller集群是因为引入了一个新的组件:controller,它替代了dledger模式故障转移的功能,可以理解为,在普通集群中引入controller即可实现故障转移,而不需要再使用dledger模式,controller组件集群本身使用的是raft算法,所以也会受限于raft算法的一些约束,比如节点数量等,不过raft算法只针对controller组件本身的主从切换,即故障转移的能力,但是只要controller主节点还在,仍然可以为broker组件服务
配置
controller组件可以单独部署,也可以部署在nameserver上,这里为了不和nameserver混淆,采用controller单独部署,如果想和nameserver部署在一起,也可以参考示例文件
1 2 3 4 5 6
| controllerDLegerGroup = group1 #DLedger Raft Group 的名字,同一个 DLedger Raft Group 保持一致即可 controllerDLegerPeers = n0-127.0.0.1:9878;n1-127.0.0.1:9868;n2-127.0.0.1:9858 #DLedger Group 内各节点的端口信息,同一个 Group 内的各个节点配置必须要保证一致 controllerDLegerSelfId = n0 #节点 id,必须属于 controllerDLegerPeers 中的一个;同 Group 内各个节点要唯一 controllerStorePath = D:\controller-n0 #controller 日志存储位置。controller 是有状态的,controller 重启或宕机需要依靠日志来恢复数据,该目录非常重要,不可以轻易删除 enableElectUncleanMaster = false #是否可以从 SyncStateSet 以外选举 Master,若为 true,可能会选取数据落后的副本作为 Master 而丢失消息,默认为 false notifyBrokerRoleChanged = true #当 Broker 副本组上角色发生变化时是否主动通知,默认为 true
|
1 2 3 4
| controllerDLegerGroup = group1 #DLedger Raft Group 的名字,同一个 DLedger Raft Group 保持一致即可 controllerDLegerPeers = n0-127.0.0.1:9878;n1-127.0.0.1:9868;n2-127.0.0.1:9858 #DLedger Group 内各节点的端口信息,同一个 Group 内的各个节点配置必须要保证一致 controllerDLegerSelfId = n1 #节点 id,必须属于 controllerDLegerPeers 中的一个;同 Group 内各个节点要唯一 controllerStorePath = D:\controller-n1 #controller 日志存储位置。controller 是有状态的,controller 重启或宕机需要依靠日志来恢复数据,该目录非常重要,不可以轻易删除
|
1 2 3 4
| controllerDLegerGroup = group1 #DLedger Raft Group 的名字,同一个 DLedger Raft Group 保持一致即可 controllerDLegerPeers = n0-127.0.0.1:9878;n1-127.0.0.1:9868;n2-127.0.0.1:9858 #DLedger Group 内各节点的端口信息,同一个 Group 内的各个节点配置必须要保证一致 controllerDLegerSelfId = n2 #节点 id,必须属于 controllerDLegerPeers 中的一个;同 Group 内各个节点要唯一 controllerStorePath = D:\controller-n2 #controller 日志存储位置。controller 是有状态的,controller 重启或宕机需要依靠日志来恢复数据,该目录非常重要,不可以轻易删除
|
controller配置完,使用mqcontroller.cmd -c <配置文件>分别启动即可
配置broker,这里只构建一个broker,两个节点,这里因为使用controller的主备切换功能,所以不需要角色相关配置,这里仅展示重要配置
1 2 3 4 5 6 7 8
| brokerClusterName = DefaultCluster brokerName = broker-a enableControllerMode = true #roker controller 模式的总开关,只有该值为 true,自动主动切换模式才会打开。默认为 false controllerAddr = 127.0.0.1:9878;127.0.0.1:9868;127.0.0.1:9858 #controller 的地址,多个 controller 中间用分号隔开 namesrvAddr = 127.0.0.1:9876 #nameserver的地址 allAckInSyncStateSet = true #若该值为 true,则一条消息需要复制到 SyncStateSet 中的每一个副本才会向客户端返回成功,可以保证消息不丢失。默认为 false listenPort = 30911 storePathRootDir=D:\store-n0
|
1 2 3 4 5 6 7 8
| brokerClusterName = DefaultCluster brokerName = broker-a enableControllerMode = true #roker controller 模式的总开关,只有该值为 true,自动主从切换模式才会打开。默认为 false controllerAddr = 127.0.0.1:9878;127.0.0.1:9868;127.0.0.1:9858 #controller 的地址,多个 controller 中间用分号隔开 namesrvAddr = 127.0.0.1:9876 #nameserver的地址 allAckInSyncStateSet = true #若该值为 true,则一条消息需要复制到 SyncStateSet 中的每一个副本才会向客户端返回成功,可以保证消息不丢失。默认为 false listenPort = 30921 storePathRootDir=D:\store-n1
|
配置完broker后,使用mqbroker.cmd -c <配置文件> 分别启动即可,部署完通过dashboard查看

问题
这次部署过程中遇到一个问题,全部启动之后,dashboard查询不到集群信息,mqadmin也查询不到broker信息,然后通过broker日志发现这个报错:
fail to send registerBrokerToController request to controller
解决办法:https://blog.csdn.net/u010600106/article/details/140011027
应该是controller的注册信息出现了问题,所以需要将相关文件删除
特点
controller集群下的broker和普通集群除了实现了故障转移,其他都是一样,所以在升级、迁移方面都非常方便
- 消息处理
- 在消息处理方面,controller集群和普通集群是一样的,并且持久化和普通集群也是一样的,所以在文件处理方面,比dledger模式更有优势
- 高可用性
- 和dledger集群一样支持broker故障转移,但是dledger集群是通过改造broker实现的,但是系统复杂度也随之变大,所以导致了不少新的问题,而controller集群在普通集群的基础上引入controller组件实现故障转移,虽然引入了新的组件,但是由于可以使用之前的代码,系统复杂度要比dledger模式小很多
- 数量要求
- 由于采用raft算法,controller组件要实现自身的故障转移仍然需要起码三个节点,但是对于broker的故障转移,controller组件哪怕只有一个主节点也可以实现,实际情况broker一般都会比controller多得多,所以在这一点上,controller比dledger系统复杂度也小了很多
- 节点复制
- 由于controller集群实际上可以理解为普通集群+controller组件,所以在节点复制方面,和普通集群是一样的,可以通过参数控制同步复制还是异步复制,比dledger模式要灵活
container集群
container集群主要目的是为了提高单节点资源利用率,实现方法为在单节点上部署多个broker,节点内的多个broker是完全隔离的,但是会复用线程、网络等资源,提高了资源利用率
rocketmq/docs/cn/BrokerContainer.md at develop · apache/rocketmq