RocketMQ broker单点宕机导致部分Topic无法发送问题分析

背景

项目生产环境的RocketMQ采用双主双从的架构, 期望达到不丢消息且高可用的目的. 而在实际的生产场景中, 我们却遭遇了当一台broker因内存不足导致java进程终止后, 部分topic消息无法正常发送的问题. 现象和预期不相符, 针对这一问题, 我们对RocketMQ相关部分的设计原理进行了更深入的研究.

设计分析

RocketMQ--

根据以上状态图可知, Producer 第一次发送会根据 AUTO_CREATE_TOPIC_KEY(TBW102) 从 NameServer 拿到 topicRouteData 作为新创建 topic 的 topicRouteData,而 Producer 中的 MQClientInstance 每30s会从 NameServer 拉取 topic 的 topicRouteData 最新信息并更新到本地内存。

  • 异常情况1

Producer 发送一条信息后关闭掉 Producer,这个时候只有在一个 broker 上面有 topic 信息,下一次启动 Producer 发送消息的时候就会直接从 NameServer 拿到最新的 topicRouteData,这样就只能在一个 master 节点上面创建 topic

  • 异常情况2

Producer 发送一条信息后,这个时候只有在一个 broker 上面有 topic 信息,隔35s在发送一条信息,在这段时间内,已经完成 MQClientInstance 对 Topic Route 的更新,topicRouteData 只会拉取到一个master节点,这样也只能在一个master节点上面创建topic

结合项目当前的Topic设计和生产环境的实际情况做进一步分析, 以成交消息为例, 我们为每个交易品种都分配了不同的topic, 很可能在某个交易上线初期只有非常少的成交发生, 这就导致了如上所述异常情况2的问题

解决方案

综合评估问题原因及解决成本等因素后, 我们决定采用如下方案对该问题进行修复:

开发程序部署到生产环境, 定时检查出路由信息只到一个broker的topic
根据该topic原本的queueNum等配置, 将其创建到其他的broker上
该程序由系统crontab调度, 每天晚上7点定时执行
一般新上交易品种开放交易的时间在晚上6点左右, 这样, 基本上在1小时内, 就能够将该交易品种对应的topic创建到各个broker上, 从而真正实现MQ的高可用

思考

对于这一问题, RocketMQ官方并不认为这是 RocketMQ 的BUG或者设计上的失误. 首先, RocketMQ的topic是一个比较重的资源, 不建议在生产环境中开启 autoCreateTopicEnable 这一配置, 而应该通过显式的方式明确地对topic进行管理. 以此展开, 交易所目前为每个交易品种分配单独topic的设计也并不是一个很好的实践.

Screen-Shot-2019-03-20-at-10.46.20-AM

更多关于本问题的讨论, 可以参考 https://github.com/apache/rocketmq/issues/566

Show Comments