无意间发现咱们 Kafka 办理渠道的服务的 open files 和 CPU 监控反常,如下图,有一台机器 CPU 和 opfen files 目标继续在高位,尤其是 open files 达到了4w+。
原因剖析
第一反应是这个服务恳求很高?可是这个服务是一个办理服务不该该有很高的恳求量才对,翻开监控一看,QPS少的不幸。
既然机器还在就找 devops 同学帮助运用 Arthas 简略看下是什么线程导致的,竟然是 GC 线程,瞬时 CPU 几乎打满了。
检查了 GC 监控,每分钟 5~6 次相比其他的正常节点要多许多,而且耗时很长。
问题节点GC Count
正常节点GC Count
应该是代码出问题了,继续求助 devops 将线上有问题的机器拉了一份 dump,运用 MAT 工具剖析了下,翻开 dump 就提示了两个风险点,两个都像是目标相关的目标。
检查概况发现两个可疑目标,一个是 60+M 的 byte[], 一个是 60+M 的 map,都是目标相关的目标,问题应该出在目标上。
开始去排查了下代码,看是否有自定义目标之类的,发现一个 job 会对目标进行操作,就把 job 停了一段时间,GC 少了许多,可是 open files 只减少了一点点, 很明显不是底子原因。
继续深化,将 byte[] 保存成字符串检查(确实文本也有60+M),发现全是 JMX 的目标数据,咱们的体系运用了两种目标一种是Micrometer,一种是 prometheus-jmx-exporter,这个 byte[] 数组便是第二种目标的数据。
而且这些目标中发现有非常多的 kafka_producer 最初的目标。
为了验证是否属于 JMX 的目标数据,再次求助 devops 拉取线上有问题机器的 JMX 目标接口, 看回来的是否是 60M+ 的目标数据,发现底子拉不下来。
到此根本承认问题出在 JMX 目标上, 那这些目标谁注册的呢?
经过目标称号在源代码里查找,发现是来自org.apache.kafka.common.network.Selector.SelectorMetrics
,是 kafka-client
注册的目标。
详细的创立顺序如下,每创立一个KafkaProducer
,就会以 client id 为仅有标识创立一个SelectorMetrics
, 而创立 KafkaProducer 会创立一个看护线程,并敞开一个长衔接定时去 Broker 拉取/更新 Metadata 信息,这个便是open files飙高的底子原因。
KafkaProducer -> Sender -> Selector -> SelectorMetrics
难道创立了许多 KafkaProducer???检查结构办法调用的地方,找到了真凶。。。
这段代码是为了支撑推迟音讯,事务服务每发一个推迟音讯,就会履行一次这段逻辑, 就会创立一个 KafkaProducer,而且会随着收到的音讯越来越多导致创立的 KafkaProducer 越来越多,直至体系无法承受。。。
庆幸的是咱们推迟音讯并不是太多,没有直接把体系给打挂掉
那为什么只要一个节点会有问题,其他节点没有问题呢?这个比较简略直接说结果了,便是这段消费逻辑消费的 topic 只要一个分区….
解决方案:
由于 Kafka 办理渠道会衔接多个 Broker,所以此处将创立的 KafkaProducer 根据 Cluster 缓存起来进行复用。
问题总结:
- KafkaProducer 本身是一个很重的目标,而且线程安全,创立的时分留意考虑场景
- 此次问题完全是凭命运提前发现了,证明监控体系也存在不够完善的地方, 咱们运用 Prometheus 的标准差函数 (stddev() by()) 配置了资源严重歪斜的监控告警,避免呈现类似的问题。