Kafka 生产运维——监控指标、常见故障与容量规划

摘要

生产环境的 Kafka 集群稳定运行,依赖三个能力:看得见(关键指标的监控与告警)、判得准(常见故障的根因分析与 SOP)、算得对(容量规划与扩缩容决策)。Kafka 通过 JMX 暴露了数百个监控指标,但真正需要关注的核心指标不超过 15 个:Consumer Lag(消费积压)是业务健康度的直接体现;Under-Replicated Partitions 是数据安全的信号灯;Broker 的网络 IO 和磁盘使用率是容量告警的触发器。本文系统梳理这三个维度,并以实际案例分析几类最常见的生产故障场景。


第 1 章 核心监控指标

1.1 Consumer Lag:业务健康度最直观的指标

Consumer Lag(消费滞后量) 是指消费者当前消费位置(Committed Offset)与 Partition 最新消息位置(Log End Offset)之间的差距,代表”还有多少消息待消费”。

Consumer Lag = Log End Offset - Committed Offset

Consumer Lag 是衡量 Kafka 下游消费健康度最直观的指标。Lag 为 0 表示消费者完全跟上了生产者;Lag 持续增大表示消费者处理速度跟不上生产速度,消息积压在增加;Lag 突然从 0 跳到很大的值,可能是 Consumer 发生了 Rebalance 或宕机。

获取 Consumer Lag 的命令

# 查看 consumer group 的 lag 详情
kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
  --describe --group my-consumer-group
 
# 输出示例:
# GROUP            TOPIC     PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG
# my-consumer-group orders   0          12345           12400           55
# my-consumer-group orders   1          8900            8900            0
# my-consumer-group orders   2          15000           15200           200

告警阈值建议

  • Lag > 某业务阈值(如 10 万条)触发 Warning;
  • Lag 持续增大(增速 > 0)且超过阈值触发 Critical;
  • 特定 Partition 的 Lag 远大于其他 Partition(数据倾斜迹象)触发调查。

1.2 Under-Replicated Partitions:数据安全的信号灯

Under-Replicated Partitions(URPs,副本不足分区数) 是指 ISR 副本数量少于配置的 replication.factor 的 Partition 数量。

# 查看所有 URPs
kafka-topics.sh --bootstrap-server localhost:9092 --describe \
  --under-replicated-partitions

URPs > 0 是一个严重的告警信号,意味着:

  • 某个 Broker 已宕机或同步严重滞后,ISR 缩减;
  • 当前的可用副本数低于期望值,系统容忍 Broker 故障的能力下降;
  • 如果持续不恢复,进一步的 Broker 宕机可能导致 acks=all 的 Producer 写入失败(min.insync.replicas 不满足)。

URPs 的常见根因

  • Broker 宕机或重启中;
  • Follower 所在 Broker 的磁盘 IO 或 CPU 压力过大,同步速度跟不上 Leader;
  • 网络分区导致 Follower 与 Leader 之间的连接中断。

1.3 其他核心指标清单

指标含义告警条件
ActiveControllerCount集群中 Active Controller 数量不等于 1 时告警(0=无 Controller,>1=脑裂)
OfflinePartitionsCount没有 Leader 的 Partition 数量> 0 触发 Critical
BytesInPerSecBroker 接收的字节速率持续超过网卡带宽 80%
BytesOutPerSecBroker 发送的字节速率(含副本同步)持续超过网卡带宽 80%
RequestsPerSec各类请求的 QPS异常飙升时调查
ProduceTotalTimeMsProducer 请求的端到端延迟(p99)超过业务 SLO
FetchConsumerTotalTimeMsConsumer Fetch 请求延迟(p99)超过业务 SLO
LogFlushRateAndTimeMs日志刷盘频率和时间刷盘时间过长影响写入延迟
ISRShrinkRateISR 缩减速率> 0 需要关注,频繁缩减需调查
LeaderElectionRateAndTimeMsLeader 选举频率频繁选举说明 Broker 不稳定

第 2 章 常见故障分析与 SOP

2.1 故障一:Consumer Lag 持续增大

症状:Consumer Lag 持续增大,消息积压越来越多,下游业务延迟增加。

根因分析步骤

步骤一:判断是生产速度加快还是消费速度降低

# 对比 Log End Offset 的增速(生产速度)
# 和 Committed Offset 的增速(消费速度)
# 如果两者同步增大,说明是生产加速
# 如果生产速度稳定但消费速度降低,说明是消费侧问题

步骤二:检查消费侧

  • Consumer GC 是否频繁(导致处理变慢);
  • Consumer 处理逻辑是否有慢查询或外部依赖(数据库超时、HTTP 慢响应);
  • Consumer 线程是否有死锁(线程 dump 分析);
  • 是否有 Rebalance 导致消费暂停(查看 Consumer 日志中的 Rebalance 事件)。

步骤三:快速缓解

  • 如果是临时峰值,等待峰值过去后 Consumer 会自动追上;
  • 如果是消费能力不足,增加 Consumer 实例(确保 ≤ Partition 数);
  • 如果需要紧急追赶历史积压,临时增加 Consumer 实例 + 临时调低业务处理逻辑的复杂度。

2.2 故障二:Under-Replicated Partitions 持续存在

症状UnderReplicatedPartitions 计数 > 0 且持续存在,某个 Follower 始终无法追上 Leader。

根因分析

# 查看具体哪些 Partition 的 ISR 不完整
kafka-topics.sh --bootstrap-server localhost:9092 \
  --describe --under-replicated-partitions
 
# 查看对应 Follower Broker 的日志
# 关注是否有 "follower is not in sync" 相关日志

常见根因:

  • Follower Broker 磁盘 IO 饱和:查看 iostat -x 1 输出,磁盘 %util 接近 100%。解决方案:迁移部分 Partition 到其他磁盘压力较小的 Broker;
  • Follower Broker JVM Full GC:GC 暂停导致 Follower 无法及时发送 Fetch 请求,被踢出 ISR。解决方案:调优 GC 参数;
  • 网络带宽不足:副本同步占用了大量带宽。解决方案:配置 replica.fetch.max.bytes 限制单次同步量,或升级网络带宽。

2.3 故障三:Broker 磁盘写满

症状:某个 Broker 的磁盘使用率达到 100%,该 Broker 上所有 Partition 的写入失败。

根因分析

  • 日志保留时间(log.retention.hours)设置过长,历史数据未及时清理;
  • 某个 Topic 的消息量突然暴涨(生产侧 Bug 导致消息洪水);
  • 磁盘容量规划不足。

紧急处理 SOP

# 1. 立即降低受影响 Topic 的保留时间,触发立即清理
kafka-configs.sh --bootstrap-server localhost:9092 \
  --alter --entity-type topics --entity-name <topic-name> \
  --add-config retention.ms=3600000  # 临时改为 1 小时
 
# 2. 手动触发日志段删除(等待 log.retention.check.interval.ms 后生效)
# 或重启 Broker 强制触发清理(有短暂不可用)
 
# 3. 恢复正常保留时间
kafka-configs.sh --bootstrap-server localhost:9092 \
  --alter --entity-type topics --entity-name <topic-name> \
  --delete-config retention.ms

第 3 章 容量规划

3.1 Partition 数量规划

Partition 数量是 Kafka 扩展性的核心参数,直接影响:

  • 最大消费并发度:Consumer Group 内最多 N(=Partition 数)个 Consumer 同时消费;
  • Producer 写入并行度:更多 Partition 可以利用更多 Broker 的写入带宽;
  • 系统开销:每个 Partition 对应若干文件句柄和内存,Partition 过多会增加 Controller、Broker 的管理开销和 Rebalance 时间。

Partition 数量估算公式

目标 Partition 数 = max(
    目标 Producer 吞吐量 / 单 Partition 写入吞吐量,
    目标 Consumer 吞吐量 / 单 Partition 消费吞吐量
)

单 Partition 的写入吞吐量通常在 10-100 MB/s 之间(取决于消息大小、压缩、网络)。实际测量时使用 kafka-producer-perf-test.sh 进行基准测试。

经验法则

  • 小集群(3 Broker):每个 Topic 建议 3-12 个 Partition;
  • 中型集群(10 Broker):每个 Topic 10-50 个 Partition,总 Partition 数不超过 10 万;
  • Partition 数量不足时可以扩容(kafka-topics.sh --alter --partitions),但 Partition 数只能增加不能减少,且增加后已有消息的分布不变(只有新消息按新 Partition 数分配),会打破 Key 哈希的一致性。

3.2 磁盘容量规划

磁盘需求(GB)= 平均消息大小(bytes)
              × 每秒消息数(messages/s)
              × 保留时间(seconds)
              × Replication Factor
              / (1024^3)
              × 1.2(20% 预留)

示例:平均消息 1KB,10 万条/秒,保留 7 天,3 副本:

= 1KB × 100000 × (7×24×3600) × 3 / 1e9 × 1.2
= 1000 × 100000 × 604800 × 3 / 1e9 × 1.2
≈ 216,576 GB ≈ 211 TB

这个数字看起来很大,但实际上:

  1. 压缩后通常减少 50-70%(使用 LZ4/Zstd);
  2. 可以通过减少保留时间来控制磁盘用量;
  3. 多个 Topic 共享 Broker 磁盘。

3.3 跨数据中心:MirrorMaker 2

MirrorMaker 2(MM2) 是 Kafka 官方的跨集群数据复制工具(Kafka 2.4+),基于 Kafka Connect 框架构建,替代了功能有限的老版 MirrorMaker 1。

MM2 的核心功能:

  • 主动-主动(Active-Active):两个数据中心互相复制对方的数据,都可以接受写入;
  • 主动-备用(Active-Standby):生产集群向备用集群单向复制,备用集群在生产集群故障时接管;
  • Topic 和 Consumer Offset 的复制:不只复制消息数据,还同步消费位置,让 Consumer 在切换到备用集群后可以从正确的位置继续消费(不重复不遗漏)。

生产避坑:MirrorMaker 2 的 Offset 映射

跨集群复制时,源集群的 Offset 与目标集群的 Offset 不一定相同(因为目标集群可能有额外的消息)。MM2 维护一个 Offset 映射表,将源集群的 Consumer Committed Offset 映射到目标集群的对应 Offset。使用 RemoteClusterUtils.translateOffsets() 可以在切换集群时正确转换 Offset。但这个机制并不完美——在极端情况下(如源集群消息写入失败、部分消息未被复制)可能出现轻微的重复或遗漏,需要业务层幂等处理兜底。


总结

本篇系统梳理了 Kafka 生产运维的三个关键维度:

监控指标:Consumer Lag(业务延迟直接体现)、Under-Replicated Partitions(数据安全信号灯)、ActiveControllerCount(集群控制面健康)是最核心的三个指标,必须有对应的告警。

常见故障 SOP:Consumer Lag 增大(排查消费侧瓶颈 → 增加 Consumer 实例)、URP 持续存在(排查 Follower IO/GC/网络 → 迁移 Partition)、磁盘写满(临时降低保留时间 + 容量扩容)。

容量规划:Partition 数量根据目标吞吐量和消费并发度估算,总数建议 < 10 万;磁盘容量按消息速率 × 保留时间 × 副本数 × 1.2 倍预留计算;跨数据中心使用 MirrorMaker 2 复制数据,注意 Offset 映射的局限性。

至此,Kafka 专栏全部 10 篇完成,完整覆盖了从架构原理到生产运维的全链路知识体系。


参考资料

  • Apache Kafka 文档,《Monitoring》《Operations》
  • Confluent Platform 监控指南
  • KIP-382: MirrorMaker 2.0
  • LinkedIn Engineering,《Kafka at Scale》

思考题

  1. 事件驱动架构(EDA)中,服务之间通过 Kafka Topic 传递事件而非直接 RPC 调用。这种解耦带来了异步处理和流量削峰的好处。但事件的顺序保证变得复杂——如果两个服务并发发布事件到同一 Topic,Consumer 看到的顺序可能与发布顺序不同。在需要严格顺序的场景(如订单状态变更),你如何保证事件的全局有序?只保证 Partition 内有序是否足够?
  2. CDC(Change Data Capture)通过 Debezium 将数据库变更实时同步到 Kafka——实现数据库到数据仓库/搜索引擎的实时同步。CDC 的一个挑战是 Schema 变更——如果源表新增了一列,下游消费者能否自动适配?Schema Registry 如何管理 Avro/Protobuf Schema 的演进?
  3. Event Sourcing 模式将业务状态存储为一系列不可变的事件(而非当前状态)。Kafka 的日志天然适合存储事件流——Log Compaction 保证每个 Key 的最新事件可查。但事件数量随时间无限增长——查询历史状态需要回放所有事件。在什么规模下’事件回放’变得不可行?Snapshot 机制如何解决?