Spring Kafka Prometheus消费lag指标显示0或NaN异常排查
环境信息
- Spring Boot:2.3.5
- spring-cloud-stream kafka-streams binder:Hoxton.SR8
- 监控组件:spring-boot-starter-actuator,通过
/prometheus端点暴露Kafka客户端原生监控指标 - 手动升级后micrometer版本:1.7.5
异常表现
Kafka消费滞后(lag)相关指标kafka_consumer_fetch_manager_records_lag、kafka_consumer_fetch_manager_records_lag_max取值完全不符合预期:
- 绝大多数场景下指标值固定为0或NaN,和
kafka-console-consumer脚本查询到的真实非零lag值不符 - 部分场景下指标值远高于实际真实lag值
异常指标样例:
kafka_consumer_fetch_manager_records_lag{appName="EventValidator.local.2",client_id="EventValidator.local.2-StreamThread-1-consumer",env="local",instanceId="2",kafka_version="2.5.1",partition="0",spring_id="streams.0",topic="event-store",} 0.0 kafka_consumer_fetch_manager_records_lag_max{appName="EventValidator.local.2",client_id="EventValidator.local.2-StreamThread-1-consumer",env="local",instanceId="2",kafka_version="2.5.1",partition="0",spring_id="streams.0",topic="event-store",} 0.0
根因分析
该异常是三层逻辑不兼容共同导致的:
- Kafka Streams运行时除了执行业务消费的StreamThread线程对应的消费者客户端,还会创建状态恢复消费者(restore consumer)、全局状态存储消费者等内部客户端,这类客户端不会消费业务topic分区,本身lag值恒为0。Hoxton.SR8版本的binder没有做客户端过滤,把内部客户端的lag指标也一并暴露,大量0值指标和业务真实指标混在一起。
- 1.5.x~1.7.x版本的micrometer采集Kafka客户端MBean指标时,没有正确处理分区重平衡阶段的临时状态,会把分区未完成赋值阶段的0值缓存住,后续不会及时更新为真实lag值;同时存在标签重复注册时旧指标值不清理的问题,会导致数值虚高。
- Hoxton.SR8版本binder默认会给Kafka MBean指标追加
spring_id自定义标签,会导致同一个消费者客户端的指标被重复注册,进一步加剧数值不更新、虚高的问题。
解决方案
按改造成本从低到高排序:
方案1:配置过滤+自定义采集规则(无需升级依赖,适合生产环境锁版本场景)
首先修改application配置,关闭默认的全量Kafka消费者指标采集,移除重复标签:
management: metrics: enable: kafka.consumer.fetch-manager: false tags: spring_id: "" endpoints: web: exposure: include: prometheus
新增自定义指标绑定配置,只采集业务消费线程的指标,过滤内部消费者:
@Configuration public class KafkaStreamMetricsConfig { @Bean public MeterBinder kafkaStreamsConsumerMetricsBinder() { return registry -> { MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); Set<ObjectName> consumerMBeans = platformMBeanServer.queryNames(new ObjectName("kafka.consumer:type=consumer-fetch-manager-metrics,client-id=*"), null); for (ObjectName mbean : consumerMBeans) { String clientId = mbean.getKeyProperty("client-id"); if (clientId.contains("StreamThread") && !clientId.contains("restore") && !clientId.contains("global")) { new KafkaClientMetrics((KafkaClient) MBeanServerInvocationHandler.newProxyInstance( platformMBeanServer, mbean, KafkaClient.class, false )).bindTo(registry); } } }; } }
注意:配置生效后会自动清理之前注册的无效0值指标,采集到的lag值和实际值偏差在1个poll周期内
方案2:升级兼容版本修复已知bug
在不升级Spring Boot 2.3.x主版本的前提下,升级存在bug的依赖到修复版本:
- 将micrometer-core、micrometer-registry-prometheus升级到1.8.8及以上(1.8.x分支为Spring Boot 2.3.x兼容分支,修复了Kafka指标缓存不更新、NaN值处理错误、重复标签注册的问题)
- 将spring-cloud-stream kafka-streams binder升级到Hoxton.SR12(Hoxton分支最终稳定版,修复了内部客户端指标无差别暴露、自定义标签重复追加的问题)
升级后无需额外自定义配置,默认即可采集到正确的lag指标。
方案3:替换lag采集方式(最高准确率,无客户端兼容问题)
如果不想处理客户端和监控组件的兼容问题,可以直接放弃客户端本地上报的lag指标,采用更准确的采集方式:
- 部署kafka-lag-exporter组件,通过Kafka AdminClient周期性拉取所有消费组的已提交offset、对应分区的最新offset,差值计算得到真实lag,该方式和
kafka-console-consumer查询的数值完全一致,不受客户端版本、重平衡、内部组件的影响 - 直接采集Kafka Broker端内置的消费组lag指标,不依赖客户端上报
内容的提问来源于stack exchange,提问作者Shades88
相关产品推荐
相关产品推荐

