背景
自建的 RocketMQ 集群部署在虚拟机上,由业务团队自行运维。这种方式存在几个明显问题:运维团队不够专业、精力有限、性能调优和监控也不够精细。经过评估,决定将 RocketMQ 迁移到公司的云平台上,由专业运维团队统一管理。
场景分析
系统中有两套 RocketMQ 集群:
-
数据同步集群:用于 Canal 同步 binlog 数据。这套可以通过暂停 Canal 推送消息,等待老 MQ 消费完在途消息,然后切换到新 MQ。利用 binlog 位点记录,重启 Canal 继续推送,确保消息不丢失也不重复。
-
业务集群:处理业务消息。由于业务 SLA 要求 99.99%,消息不能暂停写入,而且部分 topic 是顺序消息,切换方案较为复杂。
下面重点讨论业务集群的迁移方案。
Broker 权限控制
RocketMQ 的 broker 节点有三种权限设置:
brokerPermission=2:只写权限brokerPermission=4:只读权限brokerPermission=6:读写权限
通过 updateBrokerConfig 命令可以动态修改 broker 权限。例如设置只读:
bash
./mqadmin updateBrokerConfig -b x.x.x.x:10911 -n 'x.x.x.x:9876' -k brokerPermission -v 4
将 broker 设置为只读后,该 broker 的写入流量会自动分配到集群中的其他节点。
切换方案
方案一:整体切换
优点:全部 Topic 一起切换,周期短。
缺点:风险相对较高。
步骤:
- 新 broker 节点同时注册到旧 NameServer 和新 NameServer,运行一段时间稳定
- 设置新 broker 为可写不可读,在控制台导入全部 topic 和 consumer group
- 设置老 broker 为只读不可写
- 观察老 broker 消费完成剩余消息
- 设置新 broker 为可读可写
- 运行稳定后下线老 broker
- 业务系统修改 NameServer 配置,重启容器
- 运行稳定后下线老 NameServer
回退:老 broker 改为可写不可读,新 broker 改为不可写可读,等新 broker 消费完,老 broker 改为可读可写。
方案二:按 Topic 分批切换
优点:按 topic 逐个切换,风险较低。
缺点:切换周期长。
步骤:
- 新 broker 节点同时注册到旧 NameServer 和新 NameServer,运行一段时间稳定
- 在新 broker 创建 topic,设置为可写不可读,并创建对应的消费组(此时新老 broker 该 topic 双写)
- 将老 broker 的 topic 设置为只读不可写
- 观察老 broker 消费完成
- 新 broker 的 topic 设置为可读可写
- 每次切换 10% 的 topic,直到完成
- 全部切换完成后修改 NameServer 配置
- 运行稳定后下线老 NameServer
回退:老 broker 的 topic 设置为可写不可读,新 broker 的 topic 设置为不可写可读,等新 broker 消费完之后,老 broker 的 topic 设置为可读可写。
方案三:混合方案(最终采用)
结合前两个方案的优点,分阶段执行:
阶段一:新 broker 节点同时注册到旧 NameServer 和新 NameServer,运行一个星期。
阶段二:试点一个非顺序推送且消费的 topic,按方案二执行,运行一个星期。
阶段三 :筛选出顺序推送且顺序消费的 topic,在业务低峰期按方案二执行。这里有个细节:客户端默认 30 秒刷新一次 topic 配置(由 pollNameServerInterval 参数控制),切换期间可能会有相同 hash 的消息分别发送到新老 broker,导致顺序不正确。
顺序消息推送可以采取以下改善措施:
- 评估是否可以临时减少顺序消息生产者节点数量
- 如果是调度触发发送,可以先停止调度
- 将生产者
pollNameServerInterval设置为 3 秒,缩短刷新时间
阶段四:执行方案一,将剩余 topic、consumer 全量切换。此时顺序推送的 topic 已经完成切换,新 broker 不需要修改读写权限。
实操总结
试点 Topic 切换(非顺序消费场景)
- 在老集群查看 topic 的队列数和对应的 consumer
- 在新集群创建 topic
- 在新集群创建 consumer
- 老集群 topic 权限设置为只读不可写
- 老集群消费完之后 topic 权限设置为不可读不可写
- 监控确认无误
顺序消费场景
- 收集顺序消费场景的 topic
- 单独切换,使用缩短
pollNameServerInterval等措施保证顺序性
全量切换
执行方案一,将剩余 topic、consumer 全量切换,剔除已经完成的顺序消费 topic。
注意事项
-
NameServer 配置 :生产环境 NameServer 已经扩展到多个节点,各中台服务去掉自己的 rocketmq.name-server 配置,使用全局配置。如果是自定义 key,配置修改为
自定义key=${rocketmq.name-server}。 -
客户端版本升级:择机升级客户端版本到 5+,解决顺序消费重置 offset 问题。
-
权限回收:切换完成后回收老 broker 管理员账号,防止在老 broker 创建 topic。
总结
RocketMQ 的迁移上云是一个需要仔细规划的过程。根据业务场景选择合适的切换方案,做好回退预案,并在每个阶段充分观察和验证,才能保证迁移的平滑和安全。对于顺序消息这类特殊场景,需要额外的措施保证消息顺序性,不能一刀切地采用统一的切换策略。