背景
业务服务有一个流量消耗的场景,业务每产生一条流量消耗,就会发送一条mq,而我负责的服务,则会消费这条消息,做对应的业务处理。
- mq:Rocket-MQ
- mq版本;5.0
- mq云平台:aliyun Saas版 标准版
- topic类型:普通消息
- consumer-group投递顺序性:顺序投递
- 客户端版本:5.0
- 平均生产速率:200/s
- 平均堆积条数:8
- 消费最大重试次数:16
事故描述
由于是新上线的功能,还没有加监控通知,我便像往常一样,查看mq的实例仪表盘,查看各项指标。可当我看到自己负责的consumer-group在消费场景指标-消息堆积量(条)一栏,达到了113w,一下子脑袋翁的炸了,便赶紧去查看sls中的error日志和容器日志,发现全是报错的堆栈信息。
慌乱出错
此时心里慌得一匹,但没有马上做决定实施和处理,先去了一趟厕所(之前遇到问题和bug容易卡住,后来在《代码大全》里学到一招,先不做决定,走一走或者上个厕所,心态和思路都会发生变化,情绪也会稳定下来,亲测有效),然后再回来坐下。
一看消息堆积量如此之大,肯定要先找到报错的原因,根据堆栈并结合业务发现,分析原因:
- 1号凌晨,收到了上月30号的消息,跨月消费时,会进行校验,不通过,则会抛出异常。
- 一部分数据,需要先做初始化,才能正常消费后面的数据
- 一部分有时限性的其他类型消息,比如3号的消息只能3号消费,4号进来便会报错。
顺序投递模式下消费者只能按照消息分组的顺序获取消息,前面的消息没有提交完成则无法获取消费后续的消息
根据我们项目的配置,加上阅读阿里云的相关说明,确定了堆积的原因,便开始着手想解决办法。
思考之后,我有了两个选择,
- 一是丢弃这部分消息
- 二是加快消费,争取达到16次之后,自动丢弃
由于当时环境+时间,怕把相关代码改错,加上没有测试资源,于是选择了后者,通过逐步增加消费者pod数量,增加几次后,达到了20个,消费速率,也达到了4.7w/s,同时,为了加快消费速度,便将consumer-group投递顺序性改为了「并发投递」(这一选择,真的是一大败笔)。原本想着,并发投递,可以增加消费速度,可以更快的处理完挤压的消息,可却还是因为慌乱+无知,酿成大祸。
由于这个consumer-group配置为顺序投递的原因,就是因为原因2的存在。可由于改成了并发消费,导致原有的消费顺序不复存在,导致产生了大量的消息丢弃,这下,我这只蝴蝶扇了一下翅膀,导致整个太平洋都为之一振了。在发现问题时,赶紧改为了顺序投递。
配置是改回来了,可这段时间产生的问题数据要去修正啊,就只有等消费结束,去业务库捞数据回来补了
等到消费完毕,将pod数量改回原有值,同时也开始了漫长的补数据之旅
有了上面的教训,补数据的时候,谨慎值增加了100分
正确操作
由于已经有一部分数据是确定丢失了,肯定是需要手动补数据,可由于顺序投递的特性,一条报错,让后面的消息乖乖排队,便可以利用这一特性
- 消费时手动丢弃这部分无法处理的消息
- 增加pod提高消费速率
- 补数据
总结
- 遇事莫慌,冷静分析问题原因,不要放过任何一个
就像原因2,就是因为在改配置时,没有考虑到,从而造成衍生问题
- 消息堆积不可怕,可怕的是误操作,扩大「熵」
- 不要妄想一个操作,把产生的所有问题消息全都处理了
- mq进行消费时,考虑下个方面配置,完善补偿处理机制,避免消息堆积
这次的堆积,如果在编码时,考虑到产生的三个原因,其实是完全可以避免的