生产运维:集群扩缩、监控指标与故障排查
上一篇解决了安全体系的认证、授权与加密。这一篇进入生产运维。
生产运维容易被理解为"改配置 + 重启"。更准确的说法是:Kafka 集群的运维本质上是对分布式日志的分区所有权、副本状态和元数据的受控迁移,每一步操作都在改变哪些 broker 持有哪些 partition 的哪个角色。
本文只抓三个问题:如何安全地扩缩 broker,应该盯哪些 JMX 指标,以及遇到常见故障时从哪里开始排查。
集群扩缩容模型
Kafka 集群的 broker 状态可以用一个简化模型描述:
1 | |
新 broker 加入集群后不会自动承接流量,必须显式执行分区重分配。Kafka 提供 kafka-reassign-partitions.sh 工具完成这个过程。
扩容:添加新 Broker
添加 broker 分两步:启动进程,然后触发 partition 迁移。
生成重分配计划
先准备一个 JSON 文件描述要重分配的 topic:
1 | |
生成计划:
1 | |
输出两段 JSON:当前分配(可用于回滚)和建议的新分配。将建议方案保存为 reassignment.json。
执行重分配
1 | |
Kafka 在后台启动副本同步,新 follower 追赶 leader 的 log end offset,追上后加入 ISR,最后 leader 切换(如果计划包含 leader 迁移)。
监控进度
1 | |
重分配期间集群网络流量会显著上升,因为副本同步需要跨 broker 传输数据。可通过 throttle 参数限速:
1 | |
Preferred Leader 选举
重分配完成后,partition 的实际 leader 不一定是 preferred replica(replica 列表第一个)。执行 leader 平衡:
1 | |
auto.leader.rebalance.enable=true 默认开启后台自动平衡(默认每 300 秒检查一次),但在高流量场景下可能引起短暂的 leader 切换延迟,部分团队选择关闭它,改为手动触发。
缩容:安全移除 Broker
缩容必须先把 broker 上的所有 partition 迁走,再关闭进程。直接关闭进程会触发 leader 选举风暴,影响所有在该 broker 上有 leader 的 partition。
安全缩容步骤:
- 获取 broker 当前持有的所有 partition:
kafka-topics.sh --describe过滤出目标 broker - 生成迁离计划(
--broker-list不包含目标 broker) - 执行重分配,等待 verify 确认完成
- 关闭目标 broker 进程
Kafka 3.x 在 KRaft 模式下,broker 退役可以通过 kafka-remove-brokers.sh 脚本半自动化完成,自动生成迁离计划并等待完成。
关键监控指标
Kafka 通过 JMX 暴露内部状态。以下指标反映集群健康状况的关键维度。
UnderReplicatedPartitions
MBean:kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions
含义:ISR 副本数少于 replication.factor 的 partition 数量。任何非 0 值都意味着数据冗余度下降,需要立即排查。
常见原因:broker 宕机、网络分区、副本同步落后超过 replica.lag.time.max.ms(默认 30000ms)。
ActiveControllerCount
MBean:kafka.controller:type=KafkaController,name=ActiveControllerCount
含义:集群中活跃 Controller 的数量。正常值为 1,0 表示无 Controller(集群不可写),大于 1 说明 Controller 选举出现脑裂(极少见,通常伴随 ZooKeeper 或 KRaft 异常)。
OfflinePartitionsCount
MBean:kafka.controller:type=KafkaController,name=OfflinePartitionsCount
含义:没有可用 leader 的 partition 数量。此值非 0 时对应 partition 完全不可用(生产者报 LeaderNotAvailableException,消费者无法拉取)。
RequestHandlerAvgIdlePercent
MBean:kafka.server:type=KafkaRequestHandlerPool,name=RequestHandlerAvgIdlePercent
含义:请求处理线程的平均空闲比例。低于 0.3(30%)说明 broker CPU 或 I/O 成为瓶颈,请求队列开始积压,端到端延迟上升。
NetworkProcessorAvgIdlePercent
MBean:kafka.network:type=SocketServer,name=NetworkProcessorAvgIdlePercent
含义:网络层线程的平均空闲比例。低于 0.3 说明网络连接处理成为瓶颈,通常表现为客户端连接慢或请求超时。
BytesInPerSec / BytesOutPerSec
MBean:kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec 等
含义:流入和流出的字节速率。BytesOutPerSec 通常是 BytesInPerSec 的数倍(每个 consumer group 各读一份,加上副本复制流量)。突然下降说明生产者或消费者连接中断;突然上升需排查是否有未预期的流量进入。
Consumer Lag
Consumer lag 不在 broker JMX 里,通过命令行或 Prometheus exporter 观察:
1 | |
输出中的 LAG 列是当前 consumer offset 与 partition log end offset 的差值。持续增长的 lag 说明消费速度跟不上生产速度。
可运行实验
本节实验在单机 Docker Compose 环境(三个 Kafka broker)下可完整复现。
实验一:观察 Consumer Lag
1 | |
LAG 列的数值反映了生产速度与消费速度的差距。
实验二:触发 UnderReplicatedPartitions
1 | |
实验三:执行 partition 重分配
1 | |
实验四:JMX 指标采集
Kafka broker 默认在 JMX_PORT(通常 9999)暴露 JMX。使用 Prometheus JMX Exporter 可以把 JMX 指标转换为 Prometheus 格式:
1 | |
启动后 Grafana 可以直接从 /metrics 端点拉取。
故障排查流程
ISR 收缩定位
ISR 收缩(UnderReplicatedPartitions > 0)的排查顺序:
- 确认是哪些 partition 收缩:
kafka-topics.sh --describe --under-replicated-partitions - 找到落后的 follower broker:对比
LogEndOffset和HighWatermark - 检查该 broker 的 GC 日志(
/var/log/kafka/kafka-gc.log)和 server 日志(/var/log/kafka/server.log),寻找 Full GC 或 IOException - 检查磁盘 I/O:
iostat -x 1观察%util是否接近 100% - 如果是网络问题:
sar -n DEV 1或netstat -s查看丢包率
Consumer Lag 积压排查
- 确认哪个 partition 的 lag 最大
- 检查对应消费者线程是否存活:消费者日志中有无
poll()超时或 coordinator 重连 - 检查下游处理是否阻塞:消费者的业务代码(数据库写入、RPC 调用)是否有慢操作
- 如果消费者正常但 lag 持续增长:说明消费速度不足,需要扩展消费者实例(增加 consumer group 成员,前提是 partition 数量足够)
Leader 选举风暴
大量 partition 的 leader 同时切换(ActiveControllerCount 短暂为 0,然后大量 leader 变更事件)的常见原因:
- Controller 所在 broker 宕机:新 Controller 选举期间(通常数秒内)所有 leader 选举暂停
- ZooKeeper session 超时(ZooKeeper 模式):
zookeeper.session.timeout.ms过小,网络抖动导致频繁重选 - broker 进程 Full GC 时间超过心跳超时:调整 JVM 堆大小或 GC 策略(G1GC 通常比 CMS 更适合 Kafka broker)
KRaft 模式下 Controller 是 Raft quorum 中的角色,选举速度比 ZooKeeper 模式快(通常在 1 秒以内),但 quorum 中超过半数节点不可用时集群同样不可写。
OOM 与 GC 压力
Kafka broker 的堆内存默认 1GB(KAFKA_HEAP_OPTS=-Xmx1G)。生产环境建议:
- 堆:4–8GB,不超过 32GB(超过 32GB 会失去 JVM 的指针压缩优化)
- 页缓存:剩余物理内存留给操作系统页缓存(Kafka 的顺序读写性能高度依赖页缓存)
- GC 策略:G1GC,
-XX:MaxGCPauseMillis=20
OOM 触发时 broker 进程崩溃,UnderReplicatedPartitions 立刻上升。通过 -XX:+HeapDumpOnOutOfMemoryError 开启堆转储,事后用 MAT 分析泄漏点。
模式提炼
Kafka 运维的核心模式是"可观测性优先,操作不可逆性控制":
- 每个运维动作(分区迁移、broker 下线)都有对应的中间状态可以观测(
--verify、JMX 指标) - 缩容和迁移必须先完成数据迁移再做进程操作,不能靠 Kafka 自动恢复兜底
- 监控指标的告警阈值比操作手册更重要——知道"什么时候需要介入"比"介入后怎么操作"更难
这个模式在其他分布式存储系统(Elasticsearch 节点下线、HBase Region 迁移)中同样成立:数据局部性的改变必须显式完成,而不是依赖自动平衡。
工程迁移表
| Kafka 概念 | 工程等价 |
|---|---|
| partition reassignment | 数据库分片迁移(resharding),需要双写或只读期 |
| UnderReplicatedPartitions | RAID 阵列降级(有磁盘掉线,数据冗余度下降) |
| preferred leader election | 主节点回切(failback),把流量迁回原主 |
| consumer lag | 队列积压深度,等同于 MySQL slave 的 relay log 积压 |
| GC pause → ISR 收缩 | JVM STW 期间心跳超时,等同于数据库锁等待超时导致连接断开 |
| JMX exporter + Prometheus | APM 的基础设施层指标采集,等同于 Micrometer + Prometheus 的应用层指标 |
常见误解
误解一:新 broker 加入后流量会自动均衡
新 broker 加入集群后,已有 topic 的 partition 不会自动迁移到新 broker。Kafka 只会在创建新 topic 时把新 broker 纳入分配候选。扩容后必须手动执行 partition reassignment 才能让新 broker 分担负载。
误解二:auto.leader.rebalance.enable=true 是安全的
默认开启的 leader 自动平衡会在后台周期性地把 leader 迁回 preferred replica。在高流量时段这个迁移会引起短暂的 leader 不可用(通常在 10–100ms 量级),但如果集群本身不稳定(频繁 ISR 变更),自动平衡可能加剧抖动。建议评估是否在业务低峰期手动触发。
误解三:监控 consumer lag 就够了
Consumer lag 是结果指标,只告诉消费速度落后了,不告诉原因。配合 RequestHandlerAvgIdlePercent(broker 侧 CPU 压力)、GC 日志(JVM 停顿)、消费者应用日志(业务处理耗时)才能定位根因。单独盯 lag 会延误排查时间。
误解四:缩容直接关进程即可
直接关闭 broker 进程会触发该 broker 上所有 leader partition 的重新选举,ISR 中的其他副本需要竞选新 leader。在 partition 数量多(数千个)的集群里,这个过程需要数十秒,期间对应 partition 的生产者会收到 NotLeaderOrFollowerException。安全做法是先迁走所有 partition 再关闭进程。
练习
-
启动一个三 broker 的 Docker Compose Kafka 集群,创建 replication factor 为 3 的 topic,停掉一个 broker,观察
UnderReplicatedPartitions的变化,然后重启该 broker,观察 ISR 恢复过程。 -
向已有集群添加第四个 broker,使用
kafka-reassign-partitions.sh把部分 partition 迁移到新 broker,用--verify监控迁移进度,完成后执行 preferred leader election,对比迁移前后各 broker 的BytesInPerSec。 -
配置一个消费速度故意慢于生产速度的消费者(在
poll()后 sleep 500ms),用kafka-consumer-groups.sh --describe观察 lag 随时间的增长,然后启动第二个 consumer 实例加入同一 group,观察 lag 是否下降。 -
下载 Prometheus JMX Exporter,配置 Kafka broker 以 JMX Agent 模式启动,用 Prometheus + Grafana 搭建一个只包含本文六个关键指标的 dashboard,停掉一个 broker,观察 dashboard 上哪些指标率先变化。
系列导航
参考资料
- Apache Kafka 官方文档 — Operations:https://kafka.apache.org/documentation/#operations
- Apache Kafka 官方文档 — Monitoring:https://kafka.apache.org/documentation/#monitoring
- Confluent 文档 — Kafka Monitoring and Metrics Using JMX:https://docs.confluent.io/platform/current/kafka/monitoring.html
- Neha Narkhede, Gwen Shapira, Todd Palino. Kafka: The Definitive Guide. O’Reilly, Chapter 12: Administering Kafka.
- Prometheus JMX Exporter:https://github.com/prometheus/jmx_exporter
