真实面经题目 · 原创解析

Mq-Bus 数据量太大延迟怎么办?

消息总线数据量过大导致延迟时,不能只回答加消费者,而要按生产端、broker、消费者三段定位瓶颈,再做止血和长期治理。核心思路是看 TPS、lag、分区倾斜、消费耗时、失败重试、资源水位;再用扩分区、提升消费并行度、批量处理、限流削峰、幂等、死信和容量规划形成闭环。

出现于:阿里巴巴 · 后端开发

60 秒回答模板

我会先把它当成一次消息链路延迟问题处理,而不是直接加机器。第一步看监控,确认延迟来自生产速度突然增加、broker 写入或存储压力,还是消费者处理能力不足。关键指标包括 topic TPS、消费 lag、队列深度、单条处理耗时、失败重试率、broker CPU、磁盘 IO、网络带宽和 GC。第二步快速止血:消费者瓶颈就增加实例、提高线程池并发、批量拉取和批量提交;队列或分区不足就扩分区或扩队列,让更多消费者并行;生产端洪峰就限流、削峰、降级或拆分大消息。第三步控制副作用:扩分区会影响顺序性,并发消费要保证幂等,批量失败要控制回滚范围,重试要避免反复打爆系统,死信要有补偿流程。最后做容量规划和告警,包括 lag、堆积时长、消费失败率、死信量和消息大小分布。

考点 先定义延迟类型
主线 按三段定位瓶颈
易错点 只回答增加消费者数量,没有说明先定位生产端、broke…

深入解析

01

先定义延迟类型

先确认延迟是发送延迟、broker 内部堆积延迟,还是消费端处理延迟。发送端延迟表现为 producer send 耗时升高、超时或阻塞;broker 堆积表现为队列深度和 lag 增长;消费端延迟表现为拉取正常但业务处理慢。这个区分决定了解法,不能只靠增加消费者实例盲目处理。

02

按三段定位瓶颈

排查时按生产端、broker、消费者拆开看。生产端关注瞬时 TPS、批量发送、压缩、消息大小和网络耗时;broker 关注 CPU、磁盘 IO、页缓存、刷盘策略、网络带宽和分区负载倾斜;消费者关注拉取速率、业务耗时、线程池排队、慢 SQL、外部接口和失败重试。

03

lag 要看趋势和分布

消息堆积不能只看当前条数,还要看 lag 增长速度和预计追平时间。如果生产速率持续高于消费速率,lag 会越来越大;如果高峰后能快速下降,可能只是短时削峰能力不足。还要按 topic、分区、消费者组看 lag,判断整体能力不足还是局部热点。

04

扩分区提升并行度

如果 topic 的队列或分区数量太少,消费者实例再多也无法真正并行,因为同一消费者组内一个分区通常同一时刻只能由一个消费者消费。扩分区或扩队列后,再匹配消费者实例数和线程并发,才能提升有效吞吐。但扩分区可能改变 key 路由,影响顺序和热点分布。

05

优化消费者处理能力

消费者瓶颈时,要增加实例到接近分区数,并优化单实例内部处理能力。常见手段包括提高拉取批次、批量落库、异步化耗时 IO、减少同步远程调用、优化 SQL、缓存热点数据和拆分重计算逻辑。目标是提升有效消费吞吐,而不是把消息更快拉到本地排队。

06

保护下游系统

消费提速不能无限压向数据库、缓存或第三方接口,否则 MQ 延迟会转移成下游故障。需要限流、并发上限、连接池隔离、熔断降级和反压。高峰流量可以通过延迟队列、分层 topic、优先级队列或业务降级削峰,保证核心消息优先处理。

07

幂等和顺序性

提高并发、扩分区、失败重试都会放大重复消费和乱序风险。需要明确业务是否要求全局顺序、用户维度顺序或订单维度顺序;可乱序时用唯一业务 ID、去重表、状态机版本号和幂等更新,防止多扣款、多发券或重复状态变更。

08

重试死信和容量规划

失败消息如果无限重试,会占用消费者能力并放大延迟。临时失败应指数退避或延迟重试,超过次数进入死信;永久失败要记录原因并补偿。恢复后按峰值 TPS、消息大小、峰值时长、单条耗时和资源水位做容量规划,并建立 lag、失败率、死信量等告警。

易错点

  • 只回答增加消费者数量,没有说明先定位生产端、broker 和消费者端瓶颈。
  • 忽略分区或队列数量限制,以为消费者实例越多消费速度一定越快。
  • 只看当前堆积条数,不看 lag 增长趋势、分区倾斜和预计追平时间。
  • 提升并发后不提幂等,忽略重复消费、超时重投和手动重放的副作用。
  • 扩分区时不考虑顺序性,导致同一业务 key 的消息可能乱序处理。
  • 把失败消息无限重试,导致消费者能力被坏消息耗尽,延迟进一步放大。

面试官追问

消费者已经加了很多实例,为什么延迟还是高?

先看分区或队列数是否限制了消费者组并行度,如果只有少量分区,多出的实例拿不到分区就无法工作。其次看是否存在分区热点,某个 key 的消息集中到一个分区。还要看消费者内部是否被数据库、外部接口、锁竞争或线程池排队卡住。

扩分区会带来什么风险?

扩分区能提升并行消费能力,但会影响消息路由和顺序性。原来按 key 固定到某个分区的消息,在分区数变化后可能被路由到新分区,导致同一业务维度前后消息乱序。如果业务要求顺序,要设计稳定路由或迁移窗口。

批量消费失败时怎么处理?

批量消费要控制失败影响范围。可以批内逐条做幂等处理,成功的记录状态,失败的单独重试或投递到重试队列;如果用批量事务,批次不能过大,否则一次失败会导致大量消息回滚。通常要结合最大批量、最大等待时间、失败拆分和死信队列。

如何保证重复消费不会出问题?

把重复消费当成必然发生来设计。消息携带全局唯一业务 ID,消费者处理前检查去重表或业务状态;状态变更使用状态机约束;金额、库存、券等敏感操作使用唯一约束、版本号或幂等流水。这样重投、超时和手动重放都不会产生重复副作用。

下游数据库撑不住还要继续扩容消费者吗?

不能盲目扩容,否则会把压力进一步打到数据库,造成连接耗尽和慢查询堆积。更合理的是限制消费者并发、批量写入、优化 SQL、必要时缓存或分库分表,同时对生产端限流、非核心消息延后和核心链路优先消费。

怎么做容量规划避免再次积压?

用峰值生产 TPS、平均消息大小、峰值持续时间和业务 SLA 计算写入与消费能力需求,再压测单个 broker、单个分区、单个消费者实例的真实吞吐。然后确定分区数、消费者实例数、线程池并发、磁盘和网络冗余,并设置基于 lag 增速和预计清空时间的告警。