摘要:RocketMQ 运维管理。
目录
[TOC]
1 集群搭建
在 conf 目录下,RocketMQ 提供了多种 Broker 的配置文件:
broker.conf:单主,异步刷盘。2m/:双主,异步刷盘。2m-2s-async/:两主两从,异步复制,异步刷盘。2m-2s-sync/:两主两从,同步复制,异步刷盘。dledger/:Dledger 集群,至少三节点。
一般 RocketMQ 的集群部署方案推荐如下:
- 如果对高性能有比较强的诉求,使用两主两从,异步复制,异步刷盘。
- 如果对可靠性有比较强的诉求,建议使用 Dledger 集群,至少三节点。
1.1 单Master模式
这种方式风险较大,一旦Broker重启或者宕机时,会导致整个服务不可用。
- 不建议线上环境使用,可以用于本地测试。
1)启动 NameServer
1 |
|
2)启动 Broker
1 | |
1.2 多Master模式
一个集群无Slave,全是Master,例如2个Master或者3个Master,
这种模式的优缺点如下:
-
优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;
-
缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会受到影响。
1)启动NameServer
NameServer需要先于Broker启动,且如果在生产环境使用,为了保证高可用,建议一般规模的集群启动3个NameServer,各节点的启动命令相同,如下:
1 |
|
2)启动Broker集群
1 | |
-
如上启动命令是在单个NameServer情况下使用的。
-
对于多个NameServer的集群,Broker启动命令中
-n后面的地址列表用分号隔开即可,例如192.168.1.1:9876;192.161.2:9876。
1.3 多Master多Slave模式-异步复制
每个Master配置一个Slave,有多对Master-Slave,HA采用异步复制方式,主备有短暂消息延迟(毫秒级)。
这种模式的优缺点如下:
-
优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响。同时Master宕机后,消费者仍然可以从Slave消费,而且此过程对应用透明,不需要人工干预,性能同多Master模式几乎一样;
-
缺点:Master宕机,磁盘损坏情况下会丢失少量消息。
1)启动NameServer
1 |
|
2)启动Broker集群
brokerRole=ASYNC_MASTER
1 | |
1.4 多Master多Slave模式-同步双写
每个Master配置一个Slave,有多对Master-Slave,HA采用同步双写方式,即只有主备都写成功,才向应用返回成功。
这种模式的优缺点如下:
-
优点:数据与服务都无单点故障,Master宕机情况下,消息无延迟,服务可用性与数据可用性都非常高;
-
缺点:性能比异步复制模式略低(大约低10%左右),发送单个消息的RT会略高,且目前版本在主节点宕机后,备机不能自动切换为主机。
1)启动NameServer
1 |
|
2)启动Broker集群
brokerRole=SYNC_MASTER
1 | |
- 以上Broker与Slave配对是通过指定相同的BrokerName参数来配对,Master的BrokerId必须是0,Slave的BrokerId必须是大于0的数。
- 另外一个Master下面可以挂载多个Slave,同一Master下的多个Slave通过指定不同的BrokerId来区分。
- $ROCKETMQ_HOME指的RocketMQ安装目录,需要用户自己设置此环境变量。
1.5 RocketMQ 5.0 自动主从切换
RocketMQ 5.0 开始支持自动主从切换的模式,可参考以下文档
自动主从切换快速开始
前言

该文档主要介绍如何快速构建自动主从切换的 RocketMQ 集群,其架构如上图所示。
- 主要增加支持自动主从切换的Controller组件,其可以独立部署也可以内嵌在NameServer中。
详细设计思路请参考 设计思想.
详细的新集群部署和旧集群升级指南请参考 部署指南。
编译 RocketMQ 源码
1 | |
快速部署
在构建成功后
1 | |
如果上面的步骤执行成功,可以通过运维命令查看Controller状态。
1 |
|
-a 代表集群中任意一个Controller的地址
至此,启动成功,现在可以向集群收发消息,并进行切换测试了。
如果需要关闭快速集群,可以执行:
1 | |
对于快速部署,默认配置在 conf/controller/quick-start里面,默认的存储路径在 /tmp/rmqstore,且会开启一个 Controller (嵌入在 Namesrv) 和两个 Broker。
查看 SyncStateSet
可以通过运维工具查看 SyncStateSet:
1 |
|
-a 代表的是任意一个 Controller 的地址
如果顺利的话,可以看到以下内容:

查看 BrokerEpoch
可以通过运维工具查看 BrokerEpochEntry:
1 | |
-n 代表的是任意一个 Namesrv 的地址
如果顺利的话,可以看到以下内容:

切换
部署成功后,现在尝试进行 Master 切换。
首先,kill 掉原 Master 的进程,在上文的例子中,就是使用端口 30911 的进程:
1 | |
接着,用 SyncStateSet admin 脚本查看:
1 |
|
可以发现 Master 已经发生了切换。

Controller内嵌Namesvr集群部署
Controller以插件方式内嵌Namesvr集群(3个Node组成)部署,快速启动:
1 | |
或者通过命令单独启动:
1 | |
如果上面的步骤执行成功,可以通过运维命令查看Controller集群状态。
1 |
|
-a代表的是任意一个 Controller 的地址
如果controller启动成功可以看到以下内容:
1 | |
启动成功后Broker Controller模式部署就能使用Controller集群。
如果需要快速停止集群:
1 | |
使用 fast-try-namesrv-plugin.sh 脚本快速部署,默认配置在 conf/controller/cluster-3n-namesrv-plugin里面并且会启动3个Namesvr和3个Controller(内嵌Namesrv)。
Controller独立集群部署
Controller独立集群(3个Node组成)部署,快速启动:
1 | |
或者通过命令单独启动:
1 | |
如果上面的步骤执行成功,可以通过运维命令查看Controller集群状态。
1 |
|
-a代表的是任意一个 Controller 的地址
如果Controller启动成功可以看到以下内容:
1 | |
启动成功后Broker Controller模式部署就能使用Controller集群。
如果需要快速停止集群:
1 | |
使用fast-try-independent-deployment.sh 脚本快速部署,默认配置在 conf/controller/cluster-3n-independent里面并且会启动3个Controller(独立部署)组成一个集群。
注意说明
- 若需要保证Controller具备容错能力,Controller部署需要三副本及以上(遵循Raft的多数派协议)
- Controller部署配置文件中配置参数
controllerDLegerPeers中的IP地址配置成其他节点能够访问的IP,在多机器部署的时候尤为重要。例子仅供参考需要根据实际情况进行修改调整。
部署和升级指南
Controller部署
若需要保证Controller具备容错能力,Controller部署需要三副本及以上(遵循Raft的多数派协议)。
Controller若只部署单副本也能完成Broker Failover,但若该单点Controller故障,会影响切换能力,但不会影响存量集群的正常收发。
Controller部署有两种方式。
- 一种是嵌入于NameServer进行部署,可以通过配置enableControllerInNamesrv打开(可以选择性打开,并不强制要求每一台NameServer都打开)。
- 在该模式下,NameServer本身能力仍然是无状态的,也就是内嵌模式下若NameServer挂掉多数派,只影响切换能力,不影响原来路由获取等功能。
- 另一种是独立部署,需要单独部署Controller组件。
嵌入NameServer部署
嵌入NameServer部署时只需要在NameServer的配置文件中设置enableControllerInNamesrv=true,并填上Controller的配置即可。
1 | |
参数解释:
- 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。
-
scanNotActiveBrokerInterval:扫描 Broker是否存活的时间间隔。
- 其他一些参数可以参考ControllerConfig代码。
5.2.0 Controller 开始支持 jRaft 内核启动,不支持 DLedger 内核到 jRaft 内核原地升级
1 | |
jRaft 版本相关参数
- controllerType:controllerType=jRaft的时候内核启动使用jRaft,默认为DLedger。
- jRaftGroupId:jRaft Group的名字,同一个jRaft Group保持一致即可。
- jRaftServerId:标志自己节点的ServerId,必须出现在 jRaftInitConf 中。
- jRaftInitConf:jRaft Group 内部通信各节点的地址信息,用逗号分隔,是 jRaft 内部通信来做选举和复制所用的地址。
- jRaftControllerRPCAddr:Controller 外部通信的各节点的地址信息,用逗号分隔,比如 Controller 与 Broker 通信会使用该地址。
- jRaftSnapshotIntervalSecs:Raft Snapshot 持久化时间间隔。
参数设置完成后,指定配置文件启动Nameserver即可。
独立部署
独立部署执行以下脚本即可
1 | |
mqcontroller脚本在distribution/bin/mqcontroller,配置参数与内嵌模式相同。
Broker Controller模式部署
Broker启动方法与之前相同,增加以下参数
- enableControllerMode:Broker controller模式的总开关,只有该值为true,controller模式才会打开。默认为false。
- controllerAddr:controller的地址,两种方式填写。
- 直接填写多个Controller IP地址,多个controller中间用分号隔开,例如
controllerAddr = 127.0.0.1:9877;127.0.0.1:9878;127.0.0.1:9879。注意由于Broker需要向所有controller发送心跳,因此请填上所有的controller地址。 - 填写域名,然后设置fetchControllerAddrByDnsLookup为true,则Broker去自动解析域名后面的多个真实controller地址。
- 直接填写多个Controller IP地址,多个controller中间用分号隔开,例如
- fetchControllerAddrByDnsLookup:controllerAddr填写域名时,如果设置该参数为true,会自动获取所有controller的地址。默认为false。
- controllerHeartBeatTimeoutMills:Broker和controller之间心跳超时时间,心跳超过该时间判断Broker不在线。
- syncBrokerMetadataPeriod:向controller同步Broker副本信息的时间间隔。默认5000(5s)。
- checkSyncStateSetPeriod:检查SyncStateSet的时间间隔,检查SyncStateSet可能会shrink SyncState。默认5000(5s)。
- syncControllerMetadataPeriod:同步controller元数据的时间间隔,主要是获取active controller的地址。默认10000(10s)。
- haMaxTimeSlaveNotCatchup:表示slave没有跟上Master的最大时间间隔,若在SyncStateSet中的slave超过该时间间隔会将其从SyncStateSet移除。默认为15000(15s)。
- storePathEpochFile:存储epoch文件的位置。epoch文件非常重要,不可以随意删除。默认在store目录下。
- allAckInSyncStateSet:若该值为true,则一条消息需要复制到SyncStateSet中的每一个副本才会向客户端返回成功,可以保证消息不丢失。默认为false。
- syncFromLastFile:若slave是空盘启动,是否从最后一个文件进行复制。默认为false。
- asyncLearner:若该值为true,则该副本不会进入SyncStateSet,也就是不会被选举成Master,而是一直作为一个learner副本进行异步复制。默认为false。
- inSyncReplicas:需保持同步的副本组数量,默认为1,allAckInSyncStateSet=true时该参数无效。
- minInSyncReplicas:最小需保持同步的副本组数量,若SyncStateSet中副本个数小于minInSyncReplicas则putMessage直接返回PutMessageStatus.IN_SYNC_REPLICAS_NOT_ENOUGH,默认为1。
在Controller模式下,Broker配置必须设置enableControllerMode=true,并填写controllerAddr。
重要参数解析
1.写入副本参数
其中inSyncReplicas、minInSyncReplicas等参数在普通Master-Salve部署、SlaveActingMaster模式、自动主从切换架构有重叠和不同含义,具体区别如下
| inSyncReplicas | minInSyncReplicas | enableAutoInSyncReplicas | allAckInSyncStateSet | haMaxGapNotInSync | haMaxTimeSlaveNotCatchup | |
|---|---|---|---|---|---|---|
| 普通Master-Salve部署 | 同步复制下需要ACK的副本数,异步复制无效 | 无效 | 无效 | 无效 | 无效 | 无效 |
| 开启SlaveActingMaster (slaveActingMaster=true) | 不自动降级情况下同步复制下需要ACK的副本数 | 自动降级后,需要ACK最小副本数 | 是否开启自动降级,自动降级后,ACK最小副本数降级到minInSyncReplicas | 无效 | 判断降级依据:Slave与Master Commitlog差距值,单位字节 | 无效 |
| 自动主从切换架构(enableControllerMode=true) | 不开启allAckInSyncStateSet下,同步复制下需要ACK的副本数,开启allAckInSyncStateSet后该值无效 | SyncStateSet可以降低到最小的副本数,如果SyncStateSet中副本个数小于minInSyncReplicas则直接返回副本数不足 | 无效 | 若该值为true,则一条消息需要复制到SyncStateSet中的每一个副本才会向客户端返回成功,该参数可以保证消息不丢失 | 无效 | SyncStateSet收缩时,Slave最小未跟上Master的时间差,详见RIP-44 |
总结来说:
- 普通Master-Slave下无自动降级能力,除了inSyncReplicas其他参数均无效,inSyncReplicas表示同步复制下需要ACK的副本数。
- slaveActingMaster模式下开启enableAutoInSyncReplicas有降级能力,最小可降级到minInSyncReplicas副本数,降级判断依据是主备Commitlog高度差(haMaxGapNotInSync)以及副本存活情况,参考slaveActingMaster模式自动降级。
SlaveActingMaster为其他高可用部署方式,该模式下如果不使用可不参考
- 自动主从切换(Controller模式)依赖SyncStateSet的收缩进行自动降级,SyncStateSet副本数最小收缩到minInSyncReplicas仍能正常工作,小于minInSyncReplicas直接返回副本数不足,收缩依据之一是Slave跟上的时间间隔(haMaxTimeSlaveNotCatchup)而非Commitlog高度。
- 自动主从切换(Controller模式)正常情况是要求保证不丢消息的,只需设置allAckInSyncStateSet = true 即可,不需要考虑inSyncReplicas参数(该参数无效),如果副本较多、距离较远对延迟有要求,可以参考设置部分副本设置为asyncLearner。
2.SyncStateSet收缩检查配置
checkSyncStateSetPeriod 参数决定定时检查SyncStateSet是否需要收缩的时间间隔 haMaxTimeSlaveNotCatchup 参数决定备跟不上主的时间
当allAckInSyncState = true时(保证不丢消息),
- haMaxTimeSlaveNotCatchup 值越小,对SyncStateSet收缩越敏感,比如主备之间网络抖动就可能导致SyncStateSet收缩,造成不必要的集群抖动。
- haMaxTimeSlaveNotCatchup 值越大,对SyncStateSet收缩虽然不敏感,但是可能加大SyncStateSet收缩时的RTO时间。该RTO时间可以按照 checkSyncStateSetPeriod/2 + haMaxTimeSlaveNotCatchup 估算。
3.消息可靠性配置
保证 allAckInSyncStateSet = true 以及 enableElectUncleanMaster = false
4.延迟
当 allAckInSyncStateSet = true 后,一条消息要复制到SyncStateSet所有副本才能确认返回,假设SyncStateSet有3副本,其中1副本距离较远,则会影响到消息延迟。可以设置延迟最高距离最远的副本为asyncLearner,该副本不会进入SyncStateSet,只会进行异步复制,该副本作为冗余副本。
兼容性
该模式未对任何客户端层面 API 进行新增或修改,不存在客户端的兼容性问题。
Nameserver本身能力未做任何修改,Nameserver不存在兼容性问题。如开启enableControllerInNamesrv且controller参数配置正确,则开启controller功能。
Broker若设置enableControllerMode=false,则仍然以之前方式运行。若设置enableControllerMode=true,则需要部署controller且参数配置正确才能正常运行。
具体行为如下表所示:
| 旧版Nameserver | 旧版Nameserver+独立部署Controller | 新版Nameserver开启controller功能 | 新版Nameserver关闭controller功能 | |
|---|---|---|---|---|
| 旧版Broker | 正常运行,无法切换 | 正常运行,无法切换 | 正常运行,无法切换 | 正常运行,无法切换 |
| 新版Broker开启Controller模式 | 无法正常上线 | 正常运行,可以切换 | 正常运行,可以切换 | 无法正常上线 |
| 新版Broker不开启Controller模式 | 正常运行,无法切换 | 正常运行,无法切换 | 正常运行,无法切换 | 正常运行,无法切换 |
升级注意事项
从上述兼容性表述可以看出,NameServer正常升级即可,无兼容性问题。在不想升级Nameserver情况,可以独立部署Controller组件来获得切换能力。
针对Broker升级,分为两种情况:
(1)Master-Slave部署升级成Controller切换架构
可以带数据进行原地升级,对于每组Broker,停机主、备Broker,保证主、备的Commitlog对齐(可以在升级前禁写该组Broker一段时间,或则通过拷贝方式保证一致),升级包后重新启动即可。
若主备commitlog不对齐,需要保证主上线以后再上线备,否则可能会因为数据截断而丢失消息。
(2)原DLedger模式升级到Controller切换架构
由于原DLedger模式消息数据格式与Master-Slave下数据格式存在区别,不提供带数据原地升级的路径。在部署多组Broker的情况下,可以禁写某一组Broker一段时间(只要确认存量消息被全部消费即可,比如根据消息的保存时间来决定),然后清空store目录下除config/topics.json、subscriptionGroup.json下(保留topic和订阅关系的元数据)的其他文件后,进行空盘升级。
持久化BrokerID版本的升级注意事项
目前版本支持采用了新的持久化BrokerID版本,详情可以参考该文档,从该版本前的5.x升级到当前版本需要注意如下事项。
- 4.x版本升级遵守上述正常流程即可。
- 5.x非持久化BrokerID版本升级到持久化BrokerID版本按照如下流程:
升级Controller
- 将旧版本Controller组停机。
- 清除Controller数据,即默认在
~/DLedgerController下的数据文件。 - 上线新版Controller组。
在上述升级Controller流程中,Broker仍可正常运行,但无法切换。
升级Broker
- 将Broker从节点停机。
- 将Broker主节点停机。
- 将所有的Broker的Epoch文件删除,即默认为
~/store/epochFileCheckpoint和~/store/epochFileCheckpoint.bak。 - 将原先的主Broker先上线,等待该Broker当选为master。(可使用
admin命令的getSyncStateSet来观察) - 将原来的从Broker全部上线。
建议停机时先停从再停主,上线时先上原先的主再上原先的从,这样可以保证原来的主备关系。 若需要改变升级前后主备关系,则需要停机时保证主、备的CommitLog对齐,否则可能导致数据被截断而丢失。
设计思想、架构
背景
当前 RocketMQ Raft 模式主要是利用 DLedger Commitlog 替换原来的 Commitlog,使 Commitlog 拥有选举复制能力,但这也造成了一些问题:
- Raft 模式下,Broker组内副本数必须是三副本及以上,副本的ACK也必须遵循多数派协议。
- RocketMQ 存在两套 HA 复制流程,且 Raft 模式下的复制无法利用 RocketMQ 原生的存储能力。
因此我们希望利用 DLedger 实现一个基于 Raft 的一致性模块(DLedger Controller),并当作一个可选的选主组件,支持独立部署,也可以嵌入在 Nameserver 中,Broker 通过与 Controller 的交互完成 Master 的选举,从而解决上述问题,我们将该新模式称为 Controller 模式。
2 mqadmin管理工具
注意:
- 执行命令方法:
./mqadmin {command} {args}- 几乎所有命令都需要配置-n表示NameServer地址,格式为ip:port
- 几乎所有命令都可以通过-h获取帮助
- 如果既有Broker地址(-b)配置项又有clusterName(-c)配置项,则优先以Broker地址执行命令,如果不配置Broker地址,则对集群中所有主机执行命令,只支持一个Broker地址。-b格式为ip:port,port默认是10911
- 在tools下可以看到很多命令,但并不是所有命令都能使用,只有在MQAdminStartup中初始化的命令才能使用,你也可以修改这个类,增加或自定义命令
- 由于版本更新问题,少部分命令可能未及时更新,遇到错误请直接阅读相关命令源码
2.1 Topic相关
| 名称 | 含义 | 命令选项 | 说明 |
| updateTopic | 创建更新Topic配置 | -b | Broker 地址,表示 topic 所在 Broker,只支持单台Broker,地址为ip:port |
| -c | cluster 名称,表示 topic 所在集群(集群可通过 clusterList 查询) | ||
| -h- | 打印帮助 | ||
| -n | NameServer服务地址,格式 ip:port | ||
| -p | 指定新topic的读写权限( W=2|R=4|WR=6 ) | ||
| -r | 可读队列数(默认为 8) | ||
| -w | 可写队列数(默认为 8) | ||
| -t | topic 名称(名称只能使用字符 ^[a-zA-Z0-9_-]+$ ) | ||
| deleteTopic | 删除Topic | -c | cluster 名称,表示删除某集群下的某个 topic (集群 可通过 clusterList 查询) |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| -t | topic 名称(名称只能使用字符 ^[a-zA-Z0-9_-]+$ ) | ||
| topicList | 查看 Topic 列表信息 | -h | 打印帮助 |
| -c | 不配置-c只返回topic列表,增加-c返回clusterName, topic, consumerGroup信息,即topic的所属集群和订阅关系,没有参数 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| topicRoute | 查看 Topic 路由信息 | -t | topic 名称 |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| topicStatus | 查看 Topic 消息队列offset | -t | topic 名称 |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| topicClusterList | 查看 Topic 所在集群列表 | -t | topic 名称 |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| updateTopicPerm | 更新 Topic 读写权限 | -t | topic 名称 |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| -b | Broker 地址,表示 topic 所在 Broker,只支持单台Broker,地址为ip:port | ||
| -p | 指定新 topic 的读写权限( W=2|R=4|WR=6 ) | ||
| -c | cluster 名称,表示 topic 所在集群(集群可通过 clusterList 查询),-b优先,如果没有-b,则对集群中所有Broker执行命令 | ||
| updateOrderConf | 从NameServer上创建、删除、获取特定命名空间的kv配置,目前还未启用 | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -t | topic,键 | ||
| -v | orderConf,值 | ||
| -m | method,可选get、put、delete | ||
| allocateMQ | 以平均负载算法计算消费者列表负载消息队列的负载结果 | -t | topic 名称 |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| -i | ipList,用逗号分隔,计算这些ip去负载Topic的消息队列 | ||
| statsAll | 打印Topic订阅关系、TPS、积累量、24h读写总量等信息 | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -a | 是否只打印活跃topic | ||
| -t | 指定topic |
2.2 集群相关
| 名称 | 含义 | 命令选项 | 说明 |
| clusterList | 查看集群信息,集群、BrokerName、BrokerId、TPS等信息 | -m | 打印更多信息 (增加打印出如下信息 #InTotalYest, #OutTotalYest, #InTotalToday ,#OutTotalToday) |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| -i | 打印间隔,单位秒 | ||
| clusterRT | 发送消息检测集群各Broker RT。消息发往${BrokerName} Topic。 | -a | amount,每次探测的总数,RT = 总时间 / amount |
| -s | 消息大小,单位B | ||
| -c | 探测哪个集群 | ||
| -p | 是否打印格式化日志,以|分割,默认不打印 | ||
| -h | 打印帮助 | ||
| -m | 所属机房,打印使用 | ||
| -i | 发送间隔,单位秒 | ||
| -n | NameServer 服务地址,格式 ip:port |
2.3 Broker相关
| 名称 | 含义 | 命令选项 | 说明 |
| updateBrokerConfig | 更新 Broker 配置文件,会修改Broker.conf | -b | Broker 地址,格式为ip:port |
| -c | cluster 名称 | ||
| -k | key 值 | ||
| -v | value 值 | ||
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| brokerStatus | 查看 Broker 统计信息、运行状态(你想要的信息几乎都在里面) | -b | Broker 地址,地址为ip:port |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| brokerConsumeStats | Broker中各个消费者的消费情况,按Message Queue维度返回Consume Offset,Broker Offset,Diff,TImestamp等信息 | -b | Broker 地址,地址为ip:port |
| -t | 请求超时时间 | ||
| -l | diff阈值,超过阈值才打印 | ||
| -o | 是否为顺序topic,一般为false | ||
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| getBrokerConfig | 获取Broker配置 | -b | Broker 地址,地址为ip:port |
| -n | NameServer 服务地址,格式 ip:port | ||
| wipeWritePerm | 从NameServer上清除 Broker写权限 | -b | BrokerName |
| -n | NameServer 服务地址,格式 ip:port | ||
| -h | 打印帮助 | ||
| addWritePerm | 从NameServer上添加 Broker写权限 | -b | BrokerName |
| -n | NameServer 服务地址,格式 ip:port | ||
| -h | 打印帮助 | ||
| cleanExpiredCQ | 清理Broker上过期的Consume Queue,如果手动减少对列数可能产生过期队列 | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -b | Broker 地址,地址为ip:port | ||
| -c | 集群名称 | ||
| deleteExpiredCommitLog | 清理Broker上过期的CommitLog文件,Broker最多会执行20次删除操作,每次最多删除10个文件 | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -b | Broker 地址,地址为ip:port | ||
| -c | 集群名称 | ||
| cleanUnusedTopic | 清理Broker上不使用的Topic,从内存中释放Topic的Consume Queue,如果手动删除Topic会产生不使用的Topic | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -b | Broker 地址,地址为ip:port | ||
| -c | 集群名称 | ||
| sendMsgStatus | 向Broker发消息,返回发送状态和RT | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -b | BrokerName,注意不同于Broker地址 | ||
| -s | 消息大小,单位B | ||
| -c | 发送次数 |
2.4 消息相关
| 名称 | 含义 | 命令选项 | 说明 |
| queryMsgById | 根据offsetMsgId查询msg,如果使用开源控制台,应使用offsetMsgId,此命令还有其他参数,具体作用请阅读QueryMsgByIdSubCommand。 | -i | msgId |
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| queryMsgByKey | 根据消息 Key 查询消息 | -k | msgKey |
| -t | Topic 名称 | ||
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| queryMsgByOffset | 根据 Offset 查询消息 | -b | Broker 名称,(这里需要注意 填写的是 Broker 的名称,不是 Broker 的地址,Broker 名称可以在 clusterList 查到) |
| -i | query 队列 id | ||
| -o | offset 值 | ||
| -t | topic 名称 | ||
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| queryMsgByUniqueKey | 根据msgId查询,msgId不同于offsetMsgId,区别详见常见运维问题。-g,-d配合使用,查到消息后尝试让特定的消费者消费消息并返回消费结果 | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -i | uniqe msg id | ||
| -g | consumerGroup | ||
| -d | clientId | ||
| -t | topic名称 | ||
| checkMsgSendRT | 检测向topic发消息的RT,功能类似clusterRT | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -t | topic名称 | ||
| -a | 探测次数 | ||
| -s | 消息大小 | ||
| sendMessage | 发送一条消息,可以根据配置发往特定Message Queue,或普通发送。 | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -t | topic名称 | ||
| -p | body,消息体 | ||
| -k | keys | ||
| -c | tags | ||
| -b | BrokerName | ||
| -i | queueId | ||
| consumeMessage | 消费消息。可以根据offset、开始&结束时间戳、消息队列消费消息,配置不同执行不同消费逻辑,详见ConsumeMessageCommand。 | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -t | topic名称 | ||
| -b | BrokerName | ||
| -o | 从offset开始消费 | ||
| -i | queueId | ||
| -g | 消费者分组 | ||
| -s | 开始时间戳,格式详见-h | ||
| -d | 结束时间戳 | ||
| -c | 消费多少条消息 | ||
| printMsg | 从Broker消费消息并打印,可选时间段 | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -t | topic名称 | ||
| -c | 字符集,例如UTF-8 | ||
| -s | subExpress,过滤表达式 | ||
| -b | 开始时间戳,格式参见-h | ||
| -e | 结束时间戳 | ||
| -d | 是否打印消息体 | ||
| printMsgByQueue | 类似printMsg,但指定Message Queue | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -t | topic名称 | ||
| -i | queueId | ||
| -a | BrokerName | ||
| -c | 字符集,例如UTF-8 | ||
| -s | subExpress,过滤表达式 | ||
| -b | 开始时间戳,格式参见-h | ||
| -e | 结束时间戳 | ||
| -p | 是否打印消息 | ||
| -d | 是否打印消息体 | ||
| -f | 是否统计tag数量并打印 | ||
| resetOffsetByTime | 按时间戳重置offset,Broker和consumer都会重置 | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -g | 消费者分组 | ||
| -t | topic名称 | ||
| -s | 重置为此时间戳对应的offset | ||
| -f | 是否强制重置,如果false,只支持回溯offset,如果true,不管时间戳对应offset与consumeOffset关系 | ||
| -c | 是否重置c++客户端offset |
2.5 消费者、消费组相关
| 名称 | 含义 | 命令选项 | 说明 |
| consumerProgress | 查看订阅组消费状态,可以查看具体的client IP的消息积累量 | -g | 消费者所属组名 |
| -s | 是否打印client IP | ||
| -h | 打印帮助 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| consumerStatus | 查看消费者状态,包括同一个分组中是否都是相同的订阅,分析Process Queue是否堆积,返回消费者jstack结果,内容较多,使用者参见ConsumerStatusSubCommand | -h | 打印帮助 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -g | consumer group | ||
| -i | clientId | ||
| -s | 是否执行jstack | ||
| updateSubGroup | 更新或创建订阅关系 | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -b | Broker地址 | ||
| -c | 集群名称 | ||
| -g | 消费者分组名称 | ||
| -s | 分组是否允许消费 | ||
| -m | 是否从最小offset开始消费 | ||
| -d | 是否是广播模式 | ||
| -q | 重试队列数量 | ||
| -r | 最大重试次数 | ||
| -i | 当slaveReadEnable开启时有效,且还未达到从slave消费时建议从哪个BrokerId消费,可以配置备机id,主动从备机消费 | ||
| -w | 如果Broker建议从slave消费,配置决定从哪个slave消费,配置BrokerId,例如1 | ||
| -a | 当消费者数量变化时是否通知其他消费者负载均衡 | ||
| deleteSubGroup | 从Broker删除订阅关系 | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -b | Broker地址 | ||
| -c | 集群名称 | ||
| -g | 消费者分组名称 | ||
| cloneGroupOffset | 在目标群组中使用源群组的offset | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -s | 源消费者组 | ||
| -d | 目标消费者组 | ||
| -t | topic名称 | ||
| -o | 暂未使用 |
2.6 连接相关
| 名称 | 含义 | 命令选项 | 说明 |
| consumerConnection | 查询 Consumer 的网络连接 | -g | 消费者所属组名 |
| -n | NameServer 服务地址,格式 ip:port | ||
| -h | 打印帮助 | ||
| producerConnection | 查询 Producer 的网络连接 | -g | 生产者所属组名 |
| -t | 主题名称 | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| -h | 打印帮助 |
2.7 NameServer相关
| 名称 | 含义 | 命令选项 | 说明 |
| updateKvConfig | 更新NameServer的kv配置,目前还未使用 | -s | 命名空间 |
| -k | key | ||
| -v | value | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| -h | 打印帮助 | ||
| deleteKvConfig | 删除NameServer的kv配置 | -s | 命名空间 |
| -k | key | ||
| -n | NameServer 服务地址,格式 ip:port | ||
| -h | 打印帮助 | ||
| getNamesrvConfig | 获取NameServer配置 | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| updateNamesrvConfig | 修改NameServer配置 | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 | ||
| -k | key | ||
| -v | value |
2.8 其他
| 名称 | 含义 | 命令选项 | 说明 |
| startMonitoring | 开启监控进程,监控消息误删、重试队列消息数等 | -n | NameServer 服务地址,格式 ip:port |
| -h | 打印帮助 |
3 运维常见问题
3.1 RocketMQ的mqadmin命令报错问题
问题描述:有时候在部署完RocketMQ集群后,尝试执行“mqadmin”一些运维命令,会出现下面的异常信息:
1org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to <null> failed
解决方法:可以在部署RocketMQ集群的虚拟机上执行export NAMESRV_ADDR=ip:9876(ip指的是集群中部署NameServer组件的机器ip地址)命令之后再使用“mqadmin”的相关命令进行查询,即可得到结果。
3.2 RocketMQ生产端和消费端版本不一致导致不能正常消费的问题
问题描述:同一个生产端发出消息,A消费端可消费,B消费端却无法消费,rocketMQ Console中出现:
1Not found the consumer group consume stats, because return offset table is empty, maybe the consumer not consume any message的异常消息。
解决方案:RocketMQ 的jar包:rocketmq-client等包应该保持生产端,消费端使用相同的version。
3.3 新增一个topic的消费组时,无法消费历史消息的问题
问题描述:当同一个topic的新增消费组启动时,消费的消息是当前的offset的消息,并未获取历史消息。
解决方案:rocketmq默认策略是从消息队列尾部,即跳过历史消息。如果想消费历史消息,则需要设置:org.apache.rocketmq.client.consumer.DefaultMQPushConsumer#setConsumeFromWhere。常用的有以下三种配置:
- 默认配置,一个新的订阅组第一次启动从队列的最后位置开始消费,后续再启动接着上次消费的进度开始消费,即跳过历史消息;
1 | |
- 一个新的订阅组第一次启动从队列的最前位置开始消费,后续再启动接着上次消费的进度开始消费,即消费Broker未过期的历史消息;
1 | |
- 一个新的订阅组第一次启动从指定时间点开始消费,后续再启动接着上次消费的进度开始消费,和consumer.setConsumeTimestamp()配合使用,默认是半个小时以前;
1 | |
3.4 如何开启从Slave读数据功能
在某些情况下,Consumer需要将消费位点重置到1-2天前,这时在内存有限的Master Broker上,CommitLog会承载比较重的IO压力,影响到该Broker的其它消息的读与写。可以开启slaveReadEnable=true,当Master Broker发现Consumer的消费位点与CommitLog的最新值的差值的容量超过该机器内存的百分比(accessMessageInMemoryMaxRatio=40%),会推荐Consumer从Slave Broker中去读取数据,降低Master Broker的IO。
3.5 性能调优问题
异步刷盘建议使用自旋锁,同步刷盘建议使用重入锁,调整Broker配置项useReentrantLockWhenPutMessage,默认为false;异步刷盘建议开启TransientStorePoolEnable;建议关闭transferMsgByHeap,提高拉消息效率;同步刷盘建议适当增大sendMessageThreadPoolNums,具体配置需要经过压测。
3.6 在RocketMQ中 msgId 和 offsetMsgId 的含义与区别
使用RocketMQ完成生产者客户端消息发送后,通常会看到如下日志打印信息:
1 | |
- msgId,对于客户端来说msgId是由客户端producer实例端生成的,具体来说,调用方法
MessageClientIDSetter.createUniqIDBuffer()生成唯一的Id; - offsetMsgId,offsetMsgId是由Broker服务端在写入消息时生成的(采用”IP地址+Port端口”与“CommitLog的物理偏移量地址”做了一个字符串拼接),其中offsetMsgId就是在RocketMQ控制台直接输入查询的那个messageId。
持久化的唯一BrokerId
现阶段问题
在 RocketMQ 5.0.0 和 5.1.0 版本中,采用BrokerAddress作为Broker在Controller模式下的唯一标识。导致如下情景出现问题:
- 在容器或者K8s环境下,每次Broker的重启或升级都可能会导致IP发生变化,导致之前的
BrokerAddress留下的记录没办法和重启后的Broker联系起来,比如说ReplicaInfo,SyncStateSet等数据。