喜马拉雅:避开 Apache RocketMQ 常见的“坑”
2023-10-15 15:44:50
喜马拉雅作为音频分享行业的“常青树”,随着十几年来的积累,用户数据量巨大。另外,随着业务的不断发展和战略的不断调整,业务场景也是日益复杂,同时对消息中间件的需求也在与日俱增。本文将介绍喜马拉雅在使用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消息中间件。