返回

喜马拉雅:避开 Apache RocketMQ 常见的“坑”

后端

喜马拉雅作为音频分享行业的“常青树”,随着十几年来的积累,用户数据量巨大。另外,随着业务的不断发展和战略的不断调整,业务场景也是日益复杂,同时对消息中间件的需求也在与日俱增。本文将介绍喜马拉雅在使用Apache RocketMQ消息中间件的过程中遇到的一些问题,以及分享我们在解决问题时获得的经验。

RocketMQ 实践

喜马拉雅基于RocketMQ构建的消息总线解决了部分业务场景的消息解耦需求,但存在如下痛点:

痛点1:订阅管理混乱

从整体上来看,消息中间件的订阅者类型可分为三种:

  • 业务消费者: 通过RocketMQ API订阅消息,并处理业务数据。
  • 中间件监控消费者: 它监控RocketMQ的状态,如消息堆积、延迟情况等。
  • 重试消费者: 当消息消费失败时,它会将消息重新发送到队列的末尾。

实际上,我们还有第三方订阅者。对于第三方订阅者,我们无法通过RocketMQ API统一管理。第三方订阅者不仅包括离线系统,还包括一些不需要RocketMQ Client SDK的系统,如广告系统。因此,我们需要提供第三方订阅者的管理。

痛点2:生产端请求堆积

在通常情况下,RocketMQ的生产者在发送消息到Broker之前,需要先把消息缓存在生产者端。当Broker断开连接后,生产者将收不到响应,生产者缓冲区持续增加,直至生产者缓冲区满,导致无法发送新消息。

痛点3:消费者Rebalance机制需要优化

RocketMQ为了满足顺序消息处理需求,采取了锁队列的策略。消费组中一个消费者只能消费一个队列中的消息,如果有多个消费者,那么队列个数需要大于等于消费者的数量。当消费者组发生变化时,例如消费者数量增减或消费者分组变更,RocketMQ提供Rebalance接口,让所有的消费者都知晓此次变更。Rebalance后,消费组内的消费者会对Topic和队列重新分配,但这个过程是比较耗时的,而且在此期间,消息无法被消费。

解决方案

针对上述痛点,我们主要做了如下优化:

解决方案1:统一订阅管理

我们对消息中间件进行了改造,给业务系统提供第三方订阅者管理功能。业务系统可以通过HTTP接口创建第三方订阅者,并可以通过RocketMQ Dashboard查看订阅者的信息。

解决方案2:生产端缓存增强

为了减少生产端请求堆积,我们对生产端缓存进行了增强。当生产者发送消息时,生产者会将消息缓存在生产者端,当Broker断开连接后,生产者会重试发送消息,直至发送成功。在生产者缓存消息的过程中,如果生产者缓存已满,生产者会将消息持久化到本地。当Broker恢复连接后,生产者会从本地加载消息,并重新发送消息。

解决方案3:优化Rebalance机制

为了减少消费者Rebalance对消息消费的影响,我们对Rebalance机制进行了优化。首先,我们将Rebalance过程分成三个阶段:

  • 在第一阶段,所有消费者都停止消费。
  • 在第二阶段,消费者从NameServer获取Topic和队列的最新信息。
  • 在第三阶段,消费者重新开始消费。

其次,我们将第二阶段和第三阶段并行执行,减少了Rebalance的整体时间。

通过以上优化,我们解决了RocketMQ在生产环境中遇到的问题,使RocketMQ能够稳定地支持业务的快速发展。

结语

本文主要介绍了喜马拉雅在使用Apache RocketMQ消息中间件的过程中遇到的问题,以及我们在解决问题时获得的经验。我们希望通过分享我们的经验,能够帮助其他用户更好地使用RocketMQ消息中间件。