上一篇【第84篇】Kafka安全生产实战——TLS加密、SASL认证、ACL授权全套配置下一篇【第86篇】Kafka Tool工具链深度解析——这些官方工具你都用对了吗摘要Kafka集群上线了业务消息哗啦啦地跑——但你有没有想过Broker还活着吗分区副本同步正常吗消费积压了多少磁盘会不会突然满了没有监控的Kafka集群就像没有仪表盘的汽车开着开着就不知道哪一天会翻车。本文从零开始手把手教你搭建Kafka的生产级监控系统用JMX Exporter把Kafka内部指标暴露出来Prometheus定期采集Grafana画出漂亮的仪表板AlertManager在出问题时第一时间通知你。我们会详细解读每个关键指标的含义和正常范围让你不只是会搭监控更会看监控——知道什么时候该紧张什么时候可以淡定喝咖啡。一、Kafka监控的全景图先搞清楚我们要监控什么。Kafka的监控不是装个Prometheus就完事了需要从三个维度设计【Kafka监控体系全景图】 ┌─────────────────────────────────────────────────────────────────┐ │ Kafka 监控体系 │ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ Broker 监控 │ │ Producer 监控 │ │ Consumer 监控 │ │ │ │ │ │ │ │ │ │ │ │ • 集群健康状态 │ │ • 发送速率 │ │ • 消费速率 │ │ │ │ • 副本同步状态 │ │ • 发送延迟 │ │ • 消费延迟Lag │ │ │ │ • 吞吐量/带宽 │ │ • 错误率 │ │ • 分区分配 │ │ │ │ • 磁盘使用 │ │ • 请求排队 │ │ • 错误率 │ │ │ │ • JVM/OS资源 │ │ • 重试次数 │ │ • Rebalance频率 │ │ │ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │ │ │ │ │ │ │ └────────────────────┼────────────────────┘ │ │ │ │ │ ┌──────────▼──────────┐ │ │ │ JMX Exporter │ │ │ │ (指标暴露层) │ │ │ └──────────┬──────────┘ │ │ │ │ │ ┌──────────▼──────────┐ │ │ │ Prometheus │ │ │ │ (采集 存储) │ │ │ └──────────┬──────────┘ │ │ │ │ │ ┌─────────────────┼─────────────────┐ │ │ │ │ │ │ │ ┌────────▼────────┐ ┌─────▼──────┐ ┌───────▼───────┐ │ │ │ Grafana │ │ AlertManager│ │ 自定义告警 │ │ │ │ (可视化面板) │ │ (告警路由) │ │ (钉钉/企微) │ │ │ └─────────────────┘ └────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────────────┘这套体系的三个核心组件组件角色类比JMX Exporter把Kafka的JMX指标转成Prometheus格式翻译官——把Kafka的方言翻译成Prometheus能懂的普通话Prometheus定时拉取指标并存储到时序数据库巡检员——每隔一段时间去每个Broker检查指标Grafana将指标数据可视化为图表仪表盘制造商——把枯燥的数字变成直观的曲线二、第一步配置JMX ExporterKafka本身通过JMX暴露了大量内部指标但Prometheus不认识JMX。JMX Exporter就是一个桥梁——作为Java Agent嵌入Kafka进程把JMX指标转成HTTP接口供Prometheus拉取。2.1 下载并配置JMX Exporter# 下载JMX Exporter JAR包wgethttps://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.20.0/jmx_prometheus_javaagent-0.20.0.jar# 创建配置目录mkdir-p/opt/kafka/config/prometheus2.2 编写JMX Exporter配置文件/opt/kafka/config/prometheus/kafka-jmx.yml的核心内容---lowercaseOutputName:truelowercaseOutputLabelNames:true# 匹配规则只采集我们关心的指标避免爆炸式的指标数量rules:# Broker级别指标 # 集群中不同步的副本数最重要-pattern:kafka.servertypeReplicaManager,nameUnderReplicatedPartitionsValuename:kafka_server_replicamanager_underreplicatedpartitions# 当前Broker是否是集群的Controller-pattern:kafka.servertypeKafkaController,nameActiveControllerCountValuename:kafka_controller_activecontroller_count# Leader选举速率-pattern:kafka.controllertypeControllerStats,nameLeaderElectionRateAndTimeMsCountname:kafka_controller_leader_election_rate# 网络吞吐指标 # 入站消息流量bytes/s-pattern:kafka.servertypeBrokerTopicMetrics,nameBytesInPerSecOneMinuteRatename:kafka_server_brokertopicmetrics_bytesin_per_sec# 出站消息流量bytes/s-pattern:kafka.servertypeBrokerTopicMetrics,nameBytesOutPerSecOneMinuteRatename:kafka_server_brokertopicmetrics_bytesout_per_sec# 入站消息条数条/s-pattern:kafka.servertypeBrokerTopicMetrics,nameMessagesInPerSecOneMinuteRatename:kafka_server_brokertopicmetrics_messagesin_per_sec# 请求相关指标 # Produce请求总数-pattern:kafka.networktypeRequestMetrics,nameTotalTimeMs,requestProduceCountname:kafka_network_requestmetrics_produce_total# Fetch请求总数-pattern:kafka.networktypeRequestMetrics,nameTotalTimeMs,requestFetchConsumerCountname:kafka_network_requestmetrics_fetchconsumer_total# 日志和磁盘指标 # 日志刷新速率-pattern:kafka.logtypeLogFlushStats,nameLogFlushRateAndTimeMsCountname:kafka_log_logflushstats_flush_count# JVM指标 # 堆内存使用-pattern:java.langtypeMemoryHeapMemoryUsage(\w)name:jvm_memory_heap_$1# GC次数和时间-pattern:java.langtypeGarbageCollector,name(\w)(\w)name:jvm_gc_$2{collector$1}# 操作系统指标 # 文件描述符使用数-pattern:java.langtypeOperatingSystem(OpenFileDescriptorCount|MaxFileDescriptorCount)name:os_filedescriptor_$1kafka-server-start.sh中已经预留了JMX相关配置入口。在kafka-run-class.sh中默认设置了if[-z$KAFKA_JMX_OPTS];thenKAFKA_JMX_OPTS-Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.authenticatefalse \ -Dcom.sun.management.jmxremote.sslfalsefi2.3 启动Kafka时加载JMX Exporter修改KAFKA_OPTS环境变量在启动Kafka时挂载JMX ExporterexportKAFKA_OPTS-javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent-0.20.0.jar7071:/opt/kafka/config/prometheus/kafka-jmx.yml# 启动Kafkakafka-server-start.sh-daemon/opt/kafka/config/server.properties搞定后访问http://broker-host:7071/metrics就能看到Prometheus格式的指标了# HELP kafka_server_replicamanager_underreplicatedpartitions # TYPE kafka_server_replicamanager_underreplicatedpartitions gauge kafka_server_replicamanager_underreplicatedpartitions 0.0 kafka_server_brokertopicmetrics_bytesin_per_sec 1.256e06 kafka_server_brokertopicmetrics_bytesout_per_sec 3.891e06 kafka_controller_activecontroller_count 1.0三、第二步配置Prometheus采集3.1 Prometheus配置文件prometheus.ymlglobal:scrape_interval:15s# 每15秒拉取一次evaluation_interval:15s# 每15秒评估一次告警规则# 告警规则文件rule_files:-/etc/prometheus/rules/kafka_alerts.yml# 采集目标scrape_configs:-job_name:kafka-brokersstatic_configs:-targets:-broker1:7071# JMX Exporter端口-broker2:7071-broker3:7071labels:cluster:prod-cluster-01env:production-job_name:kafka-connectstatic_configs:-targets:-connect1:8080-connect2:80803.2 核心PromQL查询模板一旦数据进了Prometheus这些查询是你要刻在脑子里的监控场景PromQL 查询说明是否出现不同步分区kafka_server_replicamanager_underreplicatedpartitions 0任何0都是告警级别集群中是否只有一个Controllersum(kafka_controller_activecontroller_count)应该恒等于1集群入站流量汇总sum(kafka_server_brokertopicmetrics_bytesin_per_sec)KB/s级别集群出站流量汇总sum(kafka_server_brokertopicmetrics_bytesout_per_sec)通常比入站大消费端入站消息速率sum(rate(kafka_server_brokertopicmetrics_messagesin_per_sec[1m]))条/秒Broker个数count(kafka_server_replicamanager_underreplicatedpartitions)看活着的Broker四、关键指标深度解读4.1 UnderReplicatedPartitions —— 最不能忽视的指标这个指标的含义很简单有多少分区副本没有完全同步。【UnderReplicatedPartitions的三种场景】 正常状态: ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Broker 1 │ │ Broker 2 │ │ Broker 3 │ │ [L] P0 │ │ [F] P0 ✓ │ │ [F] P0 ✓ │ │ [F] P1 ✓ │ │ [L] P1 │ │ [F] P1 ✓ │ └──────────────┘ └──────────────┘ └──────────────┘ UnderReplicatedPartitions 0 ✅ 一切正常 Follower滞后: ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Broker 1 │ │ Broker 2 │ │ Broker 3 │ │ [L] P0 │ │ [F] P0 ✗ │ │ [F] P0 ✓ │ └──────────────┘ └──────────────┘ └──────────────┘ Broker 2的P0副本落后了! UnderReplicatedPartitions 1 ⚠️ Broker宕机: ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Broker 1 │ │ Broker 2 │ │ Broker 3 │ │ [L] P0 │ │ [F] P0 ✓ │ │ ↓ 宕机! │ └──────────────┘ └──────────────┘ └──────────────┘ Broker 3挂了P1失去Follower! UnderReplicatedPartitions 1 正常值始终为0。只要这个值不等于0就该紧张了。常见原因排查Broker挂了或网络不通 → 检查ActiveControllerCountFollower复制跟不上 → 检查磁盘IO、网络带宽ISR频繁变动 → 检查replica.lag.time.max.ms配置是否太小4.2 ActiveControllerCount —— 集群有且仅有一个大脑这个指标告诉你有多少个Broker正在充当Controller。正常值必须恒等于1。如果等于0说明集群没有Controller无法选举Leader如果大于1说明出现了脑裂两个Broker都认为自己是Controller——这是极其危险的。4.3 BytesInPerSec / BytesOutPerSec —— 集群的呼吸【Producer→Broker→Consumer 流量示意图】 ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Producer │ │ Broker │ │ Consumer │ │ │ │ │ │ │ │ 发送消息 │────────►│ BytesInPerSec│────────►│ 消费消息 │ │ │ │ (入站流量) │ │ │ └──────────────┘ │ │ └──────────────┘ │ ------------ │ │ BytesOutPerSec│ │ (出站流量) │ │ │ │ 注意 │ │ 出站 入站 │ │ 因为 │ │ 1. 多个消费者 │ │ 2. Follower │ │ 副本同步 │ └──────────────┘为什么BytesOutPerSec通常大于BytesInPerSec因为一条消息写入一次但可能被多个消费者组拉取多次还要加上Follower副本同步的流量。4.4 消费者Lag —— 业务最关心的指标Lag消费延迟 分区的最新offset - 消费者已提交的offset。这个值越大说明消费者处理能力跟不上生产者。# 命令行查看Lagkafka-consumer-groups.sh --bootstrap-server broker1:9092\--grouporder-service--describe# 输出示例# GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG# order-service order-events 0 1024 2048 1024# order-service order-events 1 512 1500 988当用Prometheus监控时Lag的计算公式是Consumer Lag HW(High Watermark) - ConsumerOffset但要注意ConsumerOffset是由消费者自己报告的并不一定实时准确。对于严格的生产环境建议额外在消费端打点记录消费延迟。五、第三步Grafana Dashboard搭建5.1 推荐Dashboard布局Grafana官方社区有很多现成的Kafka Dashboard模板最推荐的是Kafka OverviewDashboard ID: 721导入后稍作调整即可使用。如果你要从零搭建建议按这个分层来设计【推荐Dashboard布局】 ┌─────────────────────────────────────────────────────────────┐ │ Row 1: 集群概览 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌────────┐│ │ │Broker存活数 │ │Controller │ │URP (不同步 │ │在线分区 ││ │ │ Stat │ │ 状态 │ │ 分区数) │ │ 数 ││ │ │ 期望: 3 │ │ 期望: 1 │ │ 期望: 0 │ │ Stat ││ │ └─────────────┘ └─────────────┘ └─────────────┘ └────────┘│ ├─────────────────────────────────────────────────────────────┤ │ Row 2: 流量趋势折线图 │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ BytesIn/Out Per Second (集群汇总) ││ │ │ ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ BytesIn ││ │ │ ▁▂▃▄▃▂▁▂▃▄▃▂▁▂▃ BytesOut ││ │ └─────────────────────────────────────────────────────────┘│ ├─────────────────────────────────────────────────────────────┤ │ Row 3: 消费者Lag监控表格 折线图 │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ Consumer Lag by Topic/Consumer Group ││ │ │ order-service│50000│██████████████░░░░░░░░░░░│⚠️ 高Lag ││ │ │ log-service │ 100│██░░░░░░░░░░░░░░░░░░░░░│✅ 正常 ││ │ └─────────────────────────────────────────────────────────┘│ ├─────────────────────────────────────────────────────────────┤ │ Row 4: JVM OS 指标 │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ JVM Heap使用率 │ │ GC 暂停时间 │ │ │ │ (按Broker分组) │ │ (按Broker分组) │ │ │ └──────────────────────┘ └──────────────────────┘ │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ 磁盘使用率 │ │ 文件描述符 │ │ │ └──────────────────────┘ └──────────────────────┘ │ └─────────────────────────────────────────────────────────────┘5.2 各Panel的PromQL语句Broker存活数Stat面板count(kafka_server_replicamanager_underreplicatedpartitions)Controller状态Stat面板用颜色区分sum(kafka_controller_activecontroller_count)设置阈值1 绿色正常0 红色告警1 红色脑裂。URP不同步分区数Stat面板sum(kafka_server_replicamanager_underreplicatedpartitions)只要0就标红。入站流量Bytes/s——这是集群的呼吸频率sum(rate(kafka_server_brokertopicmetrics_bytesin_per_sec[1m]))出站流量Bytes/s——反映消费活跃度sum(rate(kafka_server_brokertopicmetrics_bytesout_per_sec[1m]))六、第四步AlertManager告警规则搞监控最重要的不是看图表而是出问题时有人知道。下面是一套生产级告警规则。6.1 告警规则文件kafka_alerts.ymlgroups:-name:kafka_alertsrules:# P0: 严重告警必须立即响应 # 告警1: 出现不同步分区-alert:KafkaUnderReplicatedPartitionsexpr:kafka_server_replicamanager_underreplicatedpartitions0for:1m# 持续1分钟才触发避免瞬时抖动labels:severity:criticalteam:middlewareannotations:summary:Kafka集群出现不同步分区description:Broker {{ $labels.instance }} 上有 {{ $value }} 个分区副本未同步。可能原因Broker宕机、网络分区或磁盘故障。请立即检查# 告警2: 没有活跃的Controller-alert:KafkaNoActiveControllerexpr:sum(kafka_controller_activecontroller_count) 0for:30slabels:severity:criticalteam:middlewareannotations:summary:Kafka集群没有活跃的Controllerdescription:集群中没有Broker充当Controller。分区Leader选举将失败生产和消费都会中断请立即检查ZooKeeper连接和Broker状态。# 告警3: 多个Controller脑裂-alert:KafkaMultipleControllersexpr:sum(kafka_controller_activecontroller_count)1for:1mlabels:severity:criticalteam:middlewareannotations:summary:Kafka集群出现多个Controller脑裂description:检测到 {{ $value }} 个活跃Controller。集群出现脑裂请立即排查ZK连接和网络状态# P1: 警告级别 # 告警4: 消费者Lag过高-alert:KafkaConsumerLagHighexpr:kafka_consumer_consumer_fetch_manager_records_lag_max100000for:5mlabels:severity:warningteam:businessannotations:summary:消费者组消费延迟过高description:消费者组 {{ $labels.consumer_group }} 在 Topic {{ $labels.topic }} 上累积延迟 {{ $value }} 条消息。请检查消费者处理能力和分区分配。# 告警5: Leader选举频繁-alert:KafkaHighLeaderElectionRateexpr:rate(kafka_controller_leader_election_rate[5m])0.5for:5mlabels:severity:warningteam:middlewareannotations:summary:Kafka Leader选举频率过高description:Leader选举频率为 {{ $value }}/s超过阈值。可能原因Broker不稳定、频繁下线或网络抖动。# 告警6: Broker下线-alert:KafkaBrokerDownexpr:count(kafka_server_replicamanager_underreplicatedpartitions) 3for:2mlabels:severity:criticalteam:middlewareannotations:summary:Kafka Broker下线description:集群中只有 {{ $value }} 个Broker在线期望3个。请立即检查# P2: 提醒级别 # 告警7: 磁盘使用率 80%-alert:KafkaDiskSpaceHighexpr:(1-node_filesystem_avail_bytes{mountpoint/data}/ node_filesystem_size_bytes{mountpoint/data}) * 10080for:10mlabels:severity:infoteam:opsannotations:summary:Kafka Broker磁盘使用率过高description:Broker {{ $labels.instance }} 磁盘使用率 {{ $value | humanize }}%请考虑清理旧日志或扩容。# 告警8: JVM老年代GC时间过长-alert:KafkaJVMGCTimeHighexpr:rate(jvm_gc_CollectionTime{collectorG1 Old Generation}[5m])0.2for:5mlabels:severity:warningteam:middlewareannotations:summary:Kafka JVM GC暂停时间过长description:Broker {{ $labels.instance }} 上老年代GC时间占比 {{ $value | humanizePercentage }}可能影响请求处理延迟。# 告警9: 请求延迟突然升高-alert:KafkaRequestLatencyHighexpr:rate(kafka_network_requestmetrics_produce_total[5m])100for:5mlabels:severity:warningteam:middlewareannotations:summary:Kafka Produce请求延迟升高description:Produce请求速率 {{ $value }}/s延迟可能同步升高请检查磁盘和网络状态。6.2 告警分级策略级别标签响应时间通知方式示例P0 Criticalseverity: critical5分钟内电话 企微 短信UnderReplicatedPartitions0P1 Warningseverity: warning30分钟内企微群消息Consumer Lag10万P2 Infoseverity: info1小时内邮件磁盘使用率80%6.3 AlertManager配置钉钉/企微通知# alertmanager.ymlglobal:resolve_timeout:5mroute:group_by:[alertname,severity]group_wait:10sgroup_interval:30srepeat_interval:4hreceiver:defaultroutes:-match:severity:criticalreceiver:critical-teamcontinue:true-match:severity:warningreceiver:warning-teamreceivers:-name:defaultwebhook_configs:-url:http://alert-gateway:8080/webhook-name:critical-teamwebhook_configs:-url:http://alert-gateway:8080/webhook/criticalsend_resolved:true七、常用指标速查表当你面对Grafana面板上一堆图表不知道看什么的时候先看这五个指标正常值告警阈值解读UnderReplicatedPartitions0 0非零就是大事立刻排查副本同步ActiveControllerCount1≠ 1不等于1就是集群大脑出了问题BytesInPerSec随业务波动突然归零或暴涨归零没消息进来暴涨可能被打Consumer Lag 10000 100000低于1万基本正常超过10万要关注JVM Heap Usage 80% 90%接近满时可能触发Full GC影响请求八、进阶技巧自建消费延迟监控Prometheus的Lag指标有时候不够精确因为offset提交有异步延迟对于关键业务建议在消费端自己打点publicclassLagReporter{privatefinalMeterRegistrymeterRegistry;privatefinalKafkaConsumerString,Stringconsumer;publicLagReporter(MeterRegistrymeterRegistry,KafkaConsumerString,Stringconsumer){this.meterRegistrymeterRegistry;this.consumerconsumer;}publicvoidreportLag(){// 获取消费者当前分配的分区SetTopicPartitionassignmentsconsumer.assignment();// 获取每个分区的末尾offsetMapTopicPartition,LongendOffsetsconsumer.endOffsets(assignments);for(TopicPartitiontp:assignments){// 计算Lag 最新offset - 当前位置longlagendOffsets.get(tp)-consumer.position(tp);// 注册到MicrometerPrometheus自动采集Gauge.builder(kafka.consumer.lag,()-lag).tag(topic,tp.topic()).tag(partition,String.valueOf(tp.partition())).tag(consumer_group,order-service).register(meterRegistry);}}}本篇小结Kafka监控体系的搭建遵循指标暴露 → 采集存储 → 可视化 → 告警通知四步走JMX Exporter作为桥梁把Kafka内部JMX指标翻译成Prometheus能读的HTTP接口Prometheus定时拉取存入时序数据库配合PromQL灵活查询Grafana把数据画成能看懂的趋势图关键指标一目了然AlertManager当UnderReplicatedPartitions0、Controller挂了、Lag飙高等情况出现时第一时间通知到人记住五条金科玉律URP必须为0、Controller有且仅有一个、Lag别飙太高、磁盘别满了、Broker别挂了。搞定了监控你才算真正拥有了对Kafka集群的掌控感——从祈祷别出事变成出了问题第一时间知道。上一篇【第84篇】Kafka安全生产实战——TLS加密、SASL认证、ACL授权全套配置下一篇【第86篇】Kafka Tool工具链深度解析——这些官方工具你都用对了吗