写在前面
上一篇讨论了数据安全与生命周期管理。数据从接收到最终入库,中间往往还经过消息队列和异步消费:设备上报需要解析入库,业务事件需要更新统计,日志需要经过处理后才能检索。
对于小微企业,消息组件通常已经有人搭起来了,也可能直接使用云服务。但"部署完成"和"能够稳定运行"之间,还有不少工作:消费者有没有持续处理,流量增长后是否追得上,发布是否导致消费停顿,下游变慢会不会拖住整条链路,失败的数据有没有人处理。
这些正是 SRE 需要关注的日常问题。中间件控制台显示正常、消费者进程还在,只能说明部分组件存活。要判断链路稳定,还需要把消息进入、消费执行和下游结果连起来看。
本篇的建设目标是:正常流量下持续消费,短时积压能够在约定时间内消化,异常消费能够及时发现,故障恢复后有证据说明链路已经恢复。 短时间出现积压并不一定是故障,关键在于是否超出业务允许的延迟,以及系统是否仍有恢复能力。
SRE 需要理解消息确认、消费组、分区、重试等架构机制,因为这些机制决定监控怎么看、扩容有没有用、恢复会不会带来新问题。涉及重复处理、业务状态和数据补偿的正确性,则需要研发提供可验证的能力,双方共同验收。
一、先盘清楚:谁在生产,谁在消费,最后写到哪里
小团队的消息链路可能比想象中分散。一个 Kafka 集群承载多个业务,同一个 Topic 被不同消费组读取,还有一些任务使用 RabbitMQ、Redis Stream 或数据库任务表。只记住集群地址,很难在告警时迅速判断影响。
先按业务画出实际链路。例如:
text
设备或业务服务
→ 接入与生产者
→ 消息服务(Topic / Queue)
→ 消费者(消费组 / 实例)
→ 数据库、搜索引擎或外部接口
同时标出:重试位置、失败数据去向、监控入口、各环节负责人
图上每个箭头都对应一个排查问题:有没有发送成功,消费者有没有拿到,处理有没有报错,结果有没有写入下游。如果还有采集代理、本地缓冲、转发服务,也应标出来,否则真正的积压可能发生在消息服务之外。
建议为每条核心链路保留以下信息:
| 需要登记的信息 | 对 SRE 的实际用途 |
|---|---|
| 业务用途、环境、重要等级、业务和运维负责人 | 判断影响范围,找到处理人 |
| 集群、Topic / Queue、消费组、订阅或路由关系 | 避免看错对象,发现订阅缺失或路由异常 |
| 分区或队列分布、消费实例、部署位置及资源限制 | 判断有效并行度、单点与资源瓶颈 |
| 正常和高峰流量、消息大小、允许处理延迟 | 建立容量和告警基线 |
| 下游地址、连接与调用额度、其他共享业务 | 评估扩容及追赶对下游的影响 |
| 确认方式、重试位置、失败去向、保留或过期策略 | 判断数据是否还在、是否可以恢复 |
| 看板、日志查询、受控的启停和恢复步骤 | 缩短故障定位与恢复时间 |
对于 Kafka,同一个 Topic 的不同消费组可能服务不同业务,应分别检查进度。一个组追上了,不能说明其他组也正常。RabbitMQ 的队列绑定、路由和消费者数量,也需要与业务清单对应起来。
这份清单可以先覆盖最关键的几条链路。后续新增消费者、调整订阅或切换下游时,同步更新,而不是等告警出现后再找部署记录。
二、把"消费正常"变成可以检查的标准
如果验收标准只有"进程存在"和"没有报错",很容易漏掉消费者卡住、消息被忽略、订阅错位等问题。
对 SRE 来说,一条链路至少要同时满足四个条件:
- 消息能进入。 有预期业务输入时,生产者发送和消息服务接收能够对应,失败或断流可以发现。
- 消费在推进。 有待处理数据时,消费进度持续变化,等待时间没有超过约定范围。
- 处理有结果。 成功处理和下游写入可观察,失败、重试和隔离记录都有去向。
- 故障能恢复。 消费中断后能够重新接续,在下游可承受的负载下消化积压。
允许延迟要按业务确定。报表刷新、设备数据入库和交易状态更新,对等待时间的要求并不相同。明确从哪个时间点开始计算,到哪个结果算完成,再决定告警阈值。
例如某后台统计允许五分钟延迟,可以把最老未完成任务的等待时间、统计结果的新鲜度作为主要依据,并提前设置预警。这只是口径示例,具体数值需要业务确认和运行数据支持。
还有一个容易混淆的地方:队列积压下降,可能是处理成功,也可能是消息过期、被转入失败队列,或者处理进度被人为跳过。恢复判断必须同时看消费进度和处理结果。
三、监控要覆盖消息服务、消费者和下游
小团队不必一开始就建设很复杂的监控平台,但一张用于日常判断的看板,应能把同一链路的几个关键环节放在一起。
1. 消息服务:能否持续接收和提供消息
重点查看节点可用性、连接异常、磁盘剩余空间与增长速度、磁盘读写延迟、请求延迟,以及产品对应的复制或副本健康状态。
Kafka 可以关注离线分区、同步副本不足、生产与读取请求错误;RabbitMQ 可以关注节点及队列副本状态、内存或磁盘告警、连接阻塞。托管服务也要检查配额、限流和维护事件,不能只看实例状态为"运行中"。
副本部署是否跨故障域、节点故障后是否还有足够容量,需要在架构检查和演练中确认。多个副本集中在同一台宿主机或同一故障域,仍可能同时受影响。
2. 消费者:有没有持续处理,卡在哪里
| 观察内容 | 重点指标或证据 | 可以发现的问题 |
|---|---|---|
| 输入与输出 | 接收速率、实际成功处理速率、失败速率 | 输入增长、处理能力下降、成功率异常 |
| 消费进度 | 分区或队列积压、最近推进时间 | 完全停滞、局部热点、漏掉的消费组 |
| 等待与执行 | 最老未完成任务年龄、处理耗时、端到端延迟 | 消息等待过久、处理速度变慢 |
| 在途消息 | 未确认数量、处理中的任务数 | 大量消息已取走却没有完成 |
| 实例状态 | 实例数、重启、OOM、CPU 限流、内存、连接池等待 | 实例不稳定或资源受限 |
| 消费协调 | 消费组成员、分区分配、重平衡频率 | 发布或异常退出导致反复停顿 |
| 异常去向 | 重试、重新投递、解析失败、死信及其滞留时间 | 反复失败、异常被长期搁置 |
Kafka 常见的 lag 是日志末端位置与消费组已提交位置的差值,应核实监控工具的具体口径。它能反映进度差距,但不直接等于业务未完成数量,也不是等待秒数。要同时看各分区,避免总量掩盖单个热点。
RabbitMQ 等队列中,等待投递的数量下降而未确认数量持续上升,可能意味着消息只是被预取到了消费者。此时仍需检查处理耗时和下游结果。
仅查看已完成消息的耗时也有盲区:消费者完全停止后,耗时指标可能不再更新。应补充待处理任务年龄、进度停滞和数据新鲜度;如果目前没有可靠的年龄指标,就先明确监控缺口,请研发提供必要的任务时间或处理结果指标。
指标通常按服务、消费组、队列或有限的错误类别聚合。订单号、消息 ID 等高基数信息保留在日志或查询记录中,避免监控本身产生过大负担。
3. 下游:是否拖慢了消费
消费变慢时,还要同步看数据库写入耗时、锁等待、连接数,搜索引擎写入拒绝或限流,以及外部接口超时和配额。
消费者 CPU 很低,不代表有大量可用处理能力。它可能一直在等数据库连接,也可能在等待一个超时很长的外部调用。只有把这些指标放到同一时间线上,才能判断资源应该加在哪里。
已有中间件 Exporter、云监控和应用日志的团队,可以先把这些数据关联起来。对于无法从组件侧判断的"处理成功"和"业务结果新鲜度",与研发约定最少的指标或只读查询入口,不必一次补齐全部埋点。
四、积压告警要看趋势、时效和是否还有消费
统一设置"超过一万条就报警",通常很难适用于所有链路。一万条轻量消息可能很快消化,一百个重任务却可能等待很久。
告警可以从以下几类开始:
| 告警场景 | 判断思路 | 应采取的行动 |
|---|---|---|
| 消费停止 | 存在待处理数据,但进度在约定窗口内没有推进 | 检查实例、订阅分配、错误和依赖 |
| 持续积压 | 新增速率持续超过有效处理速率,积压趋势上升 | 判断流量变化和容量缺口 |
| 超过业务时效 | 最老未完成任务或结果新鲜度超过约定值 | 确认业务影响并升级处理 |
| 异常消费增加 | 失败、重试、重新投递或死信新增明显异常 | 定位错误类型及影响范围 |
| 接近不可恢复边界 | 保留窗口、磁盘或配额余量不足 | 优先保护恢复条件并处理容量风险 |
| 预期输入中断 | 应有流量的时间段内突然无输入 | 沿生产者、路由和网络检查断流 |
对正常短峰,可以结合持续时间和历史基线减少噪声;对完全停滞、关键业务超时和数据即将过期,不应为了降低告警量而设置过长等待窗口。
低频任务要结合预期调度时间判断,不能要求每分钟都有处理量。监控采集失联也应单独识别,避免把"没有数据"当成"没有积压"。
告警中带上业务名称、消费组或队列、积压趋势、等待时间、当前处理速率、看板与日志入口,并指定负责人和升级路径。小团队可以一人兼任多个角色,但不能让告警只停留在无人认领的群消息里。
五、怎样让日常消费能力跟上业务增长
积压治理需要平时建立容量基线。至少记录正常与高峰输入速率、消息大小、实际处理速率、处理耗时,以及对应的消费者资源和下游负载。
消息数量相同,单条消息大小、解析复杂度或数据库写入量增加,也可能明显降低处理能力。因此,接入新业务、增加字段、调整批量任务或修改下游逻辑后,需要重新观察容量。
先判断是否有追赶余量
对统计范围一致、消息处理成本相对稳定的链路,可以粗略估算:
text
净消化速率 ≈ 有效处理速率 − 新增待处理速率
预计追赶时间 ≈ 当前积压量 ÷ 净消化速率
例如积压 60 万条,新消息每秒进入 200 条,实际每秒完成 500 条,理论上约需 2,000 秒,也就是 33 分钟追上。如果只能每秒完成 180 条,积压会继续增长。
有效处理速率不能直接拿"拉取次数"或包含反复重试的计数代替;失败隔离也不能算作业务成功。无法获得一致计数时,可以结合实际积压下降速度估算队列追赶时间,并单独跟踪失败任务。
估算还需要用后续趋势修正。历史消息更难处理、流量波动或热点分区,都可能让恢复慢于预期。平时容量刚好等于输入量的系统,即便正常运行时没有积压,也没有故障后的追赶余量。
扩消费者之前,检查三个限制
第一是有效并行度。Kafka 常见消费组模式下,一个分区在同一时刻由组内一个消费者负责,增加实例超过可分配分区数,通常不会继续增加有效消费并行度。只有一个热点分区时,加很多实例也未必有效。调整分区或路由需要与研发确认顺序和业务影响。
第二是下游承载能力。增加实例、线程或批量大小,可能同时增加数据库连接、写入峰值和第三方调用。要给实时业务及恢复操作留出余量,把滚动发布时的新旧实例也计入预算。
第三是单实例运行边界。检查容器资源限制、CPU 限流、内存、GC、连接池和消息预取量。盲目增加预取或批量大小,可能让等待中的消息占满内存,导致 OOM 和反复重投。
小团队可以先使用有上限的人工扩容和限速步骤。需要自动扩容时,再把积压或等待时间纳入策略,同时设置实例上限、下游容量边界和扩缩容稳定窗口,避免频繁变化造成消费组反复重平衡。
保留策略也是容量的一部分。消息保留时间和空间应覆盖故障发现、修复、追赶及必要重放的窗口。Kafka 的保留通常不会等待所有消费组追上;其他队列的 TTL、长度限制和溢出策略也要核实。延长保留需要空间支持,已经过期的数据不会因此自动恢复。
六、发生积压时,SRE 按什么顺序排查
收到告警后,先确认受影响的业务、消费组、分区或队列,以及最老等待时间。随后对齐告警开始时间、发布记录、流量变化和下游指标,逐步缩小范围。
| 观察到的现象 | 优先检查 | 处置方向 |
|---|---|---|
| 输入突然增长,消费能力基本不变 | 活动流量、补传、批任务、重复发送 | 按优先级限制非核心输入,评估扩容和追赶时间 |
| 所有分区消费同时下降 | 消费部署、公共依赖、权限、网络、消息服务 | 恢复共同故障点,核查近期变更 |
| 少数分区积压,其余正常 | 分区分配、热点业务、固定位置重复报错 | 明确热点或阻塞原因,与研发协同处理 |
| 消费者频繁重启或 OOM | 重启事件、退出原因、资源限制、消息大小及预取 | 按证据调整资源或消费配置,必要时回滚变更 |
| CPU 不高但耗时上升 | 连接池、数据库锁、下游超时和限流 | 先恢复或保护下游,控制消费并发 |
| 发布后频繁重平衡 | 实例启停、处理超时、健康检查、组成员变化 | 稳定部署,核实退出和超时配置 |
| 积压下降但结果没有增加 | 解析失败、过滤、重试转移、过期、订阅或目标错误 | 查询样本链路,确认异常去向和实际写入位置 |
日志排查时保留消费组、分区与位置、消息或业务标识、错误类型和应用版本。连续多次失败是否停在同一位置,是区分"某条异常消息阻塞"与"整体能力不足"的重要线索。
重启有时能够恢复进程,但在操作前应尽量保留错误、资源和进度信息。若原因是下游持续阻塞或固定消息解析失败,反复重启可能带来更多重投和重平衡,无法消除根因。
处置动作应与证据对应:容量不足时扩有效容量,下游故障时先保护下游,发布回归时评估回滚,异常消息时使用已有且经过验证的隔离流程。涉及消息格式、过滤逻辑或处理结果异常时,交由研发定位和修复,同时由 SRE 控制影响范围并跟踪恢复。
七、异常消费也要单独治理
没有积压,只能说明当前看到的队列没有明显等待,无法证明消息处理正确。SRE 还要关注以下异常信号:
- 解析失败或特定错误突然增加,尤其是版本发布之后。
- 同一消息反复重试,处理计数很高,实际成功量没有增长。
- 死信或失败任务持续增加,却没有对应处理人。
- 输入仍正常,下游数据长时间不更新。
- 重复处理、乱序或过期处理造成业务异常,由应用指标、核对结果或用户反馈暴露。
关键是把这些现象变成可观察、可处理的运维对象。对于重试链路,核实次数或总时长是否有上限、失败后在哪里、会不会长期占用正常消费资源。对于死信或失败任务,监控新增数量和最老未解决时间,并登记处理状态。
失败被隔离后,正常消费可以恢复,但这批失败数据仍需要闭环。 修复后是否重放、是否已经过业务有效期、会不会重复产生外部效果,需要业务和研发确认,SRE 按核定范围控制执行节奏并观察结果。
架构机制需要理解到什么程度
下面这些问题影响运维操作,应该与研发在上线前确认,并留下验证结果:
| 要确认的能力 | 为什么影响 SRE 的操作 |
|---|---|
| 消费确认或进度提交代表什么,是否对应实际处理完成 | 决定能否依据进度判断恢复,进程中断后是否可能漏处理 |
| 重启、超时和重放是否会重复投递,重复处理如何验收 | 决定重启和补数据的风险,不能默认重放安全 |
| 消息是否有顺序要求 | 决定能否调整并发、分区或隔离失败消息后继续处理 |
| 不兼容格式、持续失败消息如何处理 | 决定异常是否拖住整个分区,以及能否安全隔离 |
| 结果未知或遗漏的数据如何查询和补偿 | 决定恢复后怎样确认业务结果,谁负责修复差异 |
这些能力由研发实现并解释业务语义,SRE 将其纳入配置检查、变更评估、演练和恢复验收。若能力缺失,应记录为稳定性建设缺口,明确负责人;不能用增加监控来代替正确性保障。
八、恢复消费时,避免把积压变成下游故障
消费者停了一小时,恢复后集中处理历史消息,负载可能远高于平时。此时"全部拉满追赶"容易挤占数据库和实时业务资源。
恢复前先保存积压、消费进度、错误和版本信息,确认消息是否仍在保留范围内,以及恢复操作是否可能引起重复。随后按照既定预案执行:
- 修复阻塞原因,选少量实例或小批任务验证能够成功处理。
- 设置初始消费速率和并发上限,同时观察实时业务和下游负载。
- 在成功率正常、积压持续下降、下游仍有余量时逐步放量。
- 如果接口延迟、锁等待、限流或消费错误明显恶化,降低追赶速度,必要时暂停历史重放。
- 回到稳态后检查失败任务和业务结果,记录遗留问题及负责人。
恢复目标至少包含:消费进度持续推进、等待时间回到约定范围、异常没有继续扩大、下游运行稳定。历史消息是否完整处理,则使用研发提供的只读核对入口、任务状态或对账结果验证。
消费进度调整、清空队列和大范围重放,都应按数据变更管理,写明范围、执行依据、恢复方式和确认人。不能为了消除告警直接跳过历史数据。需要重放时,还要确认旧格式兼容、重复处理及短信、支付等外部效果。
如果下游数据库刚恢复到历史时间点,消息消费进度可能已经向前推进。这时需要研发与 SRE 一起核定缺口和补偿范围,单纯恢复消费者不一定能补齐缺失数据。
九、用演练验证,而不是等生产事故证明
第二篇的上线验收已经要求观察积压和恢复过程。到了日常稳定性建设阶段,应把关键故障场景定期验证,并在业务量或架构明显变化后复查。
先在隔离环境中使用可核对的数据,避免测试触发真实扣款、短信等外部操作。SRE 负责组织故障注入、监控与恢复观察,研发协助核对消费及业务结果。
| 演练场景 | SRE 重点验证 | 应留下的证据 |
|---|---|---|
| 暂停消费者,同时持续输入 | 告警是否到达,恢复后能否在目标时间追上 | 发现时间、等待峰值、追赶耗时和结果核对 |
| 在预定负载范围内提高输入 | 消费容量边界、预警是否提前、下游是否受影响 | 输入输出曲线、资源瓶颈及容量余量 |
| 模拟下游变慢或不可用 | 消费是否受控,有无无上限重试、连接耗尽和 OOM | 故障期间及恢复后的消费与下游指标 |
| 滚动发布或退出单个消费者 | 分区接管、重平衡、退出处理和恢复表现 | 停顿时间、实例事件及重复或遗漏核对 |
| 注入无法正常处理的测试消息 | 错误可见性、隔离去向、正常消费是否受影响 | 告警、失败记录及后续处理结果 |
| 小范围重放已处理测试数据 | 操作可控,重复处理结果符合约定 | 重放范围、执行速率及研发核对结果 |
托管消息服务可先核实厂商高可用能力和维护机制,再在允许的测试范围验证故障切换。演练目标应包括发现、响应、恢复和结果验证,不能只记录"最后程序又跑起来了"。
十、小团队如何分阶段落地
对于只有一两个人承担运维职责的团队,先从核心链路做起,按风险排序补齐。
| 阶段 | 先完成的工作 | 验收依据 |
|---|---|---|
| 看得清 | 核心链路清单、负责人、业务延迟要求、统一看板 | 能找到每条核心链路及其消费和下游状态 |
| 发现得早 | 停滞、持续积压、异常消费、容量与保留告警 | 受控故障能够通知到人,并定位到业务 |
| 恢复可控 | 排查步骤、限速和扩容边界、回滚与追赶预案 | 演练中按目标恢复,下游没有被补数据拖垮 |
| 持续改进 | 高峰容量复查、失败任务清理、变更检查和复盘 | 重复出现的问题有负责人、有修复验证 |
日常由监控发现异常;每周检查长期失败任务、积压趋势、容量增长和未解决缺口;发布或扩容前检查格式兼容、消费并行度、下游预算及回滚影响;重大变化后重新演练。
SRE 负责让链路可观察、容量有依据、操作有边界、恢复有证据。研发负责处理逻辑和业务正确性,并提供必要的指标、查询与补偿能力。业务负责人确认延迟容忍度和任务优先级。小团队可以兼任职责,但这些判断需要明确归属。
结语
消息链路的稳定性要体现在持续运行的结果上:输入来了能够处理,短时积压能够消化,异常消费有人发现,故障后能够在下游承受范围内恢复。
小微企业可以先选一条核心链路,把清单、监控、容量、排查和演练串起来。日常运行中逐步补齐薄弱环节,比单独盯着中间件是否存活,更能说明业务是否稳定。
排查消费停滞、解析失败和下游写入异常,都需要可关联的日志证据。下一篇将进入日志体系,讨论从日志输出规范到采集、存储与告警,如何为这些日常排查和稳定性判断提供支撑。