首页 / m.itcdj.com / 正文

消息队列积压排查与扩容实战手记

上周三凌晨两点,我刚把最后一口泡面汤喝完,钉钉的告警弹窗直接砸在屏幕上——Kafka消费组滞后量飙到了1200万。

群里瞬间炸了,负责支付的开发第一时间@运维,问能不能赶紧加机器把积压清了。我当时盯着面板愣了三秒,先给那个跑了半年没动过的consumer pod打了个jstack。

告警响了先别慌 别上来就点扩容按钮

真的,别上来就扩容。

很多团队的开发或者运维刚看到告警面板上跳红的滞后量,第一反应就是点控制台的扩容按钮,把consumer的副本数往上拉个三五倍,完全不管下游的系统能不能扛得住这波突然涨上来的流量。上次我们组的新人刚碰到积压告警,二话不说就加了20个consumer实例,结果下游的用户行为MySQL表直接被打挂,行锁等了个天荒地老,积压量反而从800万翻到了2000万,那天晚上我们熬到四点才把窟窿补上。

Kafka消费组滞后量监控告警截图

说实话,扩容从来不是解决积压的第一选项。你连为什么堵都没搞清楚,加再多的消费实例都是白搭——甚至可能因为消费请求太猛,把本来就脆弱的下游系统直接冲垮,雪上加霜。

顺着消息链路摸 别漏了藏得深的堵点

我现在碰到积压告警,第一时间不会看consumer的CPU使用率,反而先抓个线程栈看看。很多时候consumer的CPU连20%都不到,不代表它消费能力够——可能所有线程都卡在等第三方接口的响应上,可能卡在数据库连接池的等待队列里,可能卡在某个写死的Redis连接超时上,根本没在真正处理消息。

上次我们碰到过一次离谱的堵点:内容审核的第三方接口因为证书过期,所有请求都卡在TLS握手阶段,100个消费线程全挂在那,消息进了消费逻辑就再也出不来,滞后量每分钟涨几十万。我们当时临时把非核心的UGC审核消息降级,把线程腾给核心的交易回调消息,10分钟就把核心链路的积压清完了,根本没动扩容的事。

摸链路的时候也别只盯着消费端。有时候堵点在broker本身:是不是磁盘写满了导致消息刷不进去?是不是某个分区的leader挂了,新的分区同步还没完成?甚至有时候生产端突然爆量——比如某次直播的优惠券发放,生产端的流量比平时高了12倍,消费端还按着平时的配置跑,不堵才怪。

消息队列全链路监控拓扑图
消息队列全链路监控拓扑图

对了,还有个很多人会漏的细节:看一下最近有没有发版变更。我见过至少三次积压事故,全是开发改消费逻辑的时候,不小心在循环里加了个远程调用,本来一条消息处理只要10ms,现在变成了200ms,消费速度直接掉了20倍,找半天都找不到原因。

真要扩容的时候 别踩那些低级配置坑

真要扩容的时候 别踩那些低级配置坑
真要扩容的时候 别踩那些低级配置坑

等你真的确认了就是消费能力跟不上,要扩容了,也别闭着眼加实例。

首先要记住个死规则:consumer的实例数量不能超过对应topic的分区数。多出来的consumer根本分不到分区,只会在那空跑占资源,一点用都没有。上次我们碰到过个团队,为了清积压把consumer加到了100个,结果topic只有16个分区,84个实例全在那等着分任务,白白浪费了好多云资源,说出来都好笑对吧。

扩容的时候也别一下子把消费并发拉满。原来每个consumer是10个线程处理消息,你一下子调到50,下游数据库的连接数直接被打满,到时候又得花时间救场。慢慢加,每加一批就观察个10分钟,看滞后量是不是在稳定下降,下游的监控指标有没有飘红,稳着来比什么都强。

真碰到那种积压量特别大的极端情况,比如节假日大促之后积压了几千万条历史消息,常规扩容追不上的时候,也可以搞点旁门左道:临时开个低优先级的消费组,先把积压的消息捞出来写到对象存储里,等业务高峰过了再慢慢回放处理,别硬扛着把核心业务的资源给占了。

那次凌晨的1200万积压,最后查下来就是第三方审核接口的问题,我们临时调了下消费的优先级,把非核心消息的消费线程先停了,不到半小时就把核心链路的滞后量降到了正常范围,之前新人加的20个consumer实例,第二天上班就全给删了。

不过话说回来,谁没在消息队列上踩过几个坑呢?平时多盯着点监控面板,多压测下消费链路的能力,真碰到告警的时候,也不至于手忙脚乱。