36 你应该怎么监控Kafka?
你好,我是胡夕。今天我要和你分享的主题是:如何监控Kafka。
监控Kafka,历来都是个老大难的问题。无论是在我维护的微信公众号,还是Kafka QQ群里面,大家问得最多的问题,一定是Kafka的监控。大家提问的内容看似五花八门,但真正想了解的,其实都是监控这点事,也就是我应该监控什么,怎么监控。那么今天,我们就来详细聊聊这件事。
我个人认为,和头疼医头、脚疼医脚的问题类似,在监控Kafka时,如果我们只监控Broker的话,就难免以偏概全。单个Broker启动的进程虽然属于Kafka应用,但它也是一个普通的Java进程,更是一个操作系统进程。因此,我觉得有必要从Kafka主机、JVM和Kafka集群本身这三个维度进行监控。
主机监控
主机级别的监控,往往是揭示线上问题的第一步。所谓主机监控,指的是监控Kafka集群Broker所在的节点机器的性能。通常来说,一台主机上运行着各种各样的应用进程,这些进程共同使用主机上的所有硬件资源,比如CPU、内存或磁盘等。
常见的主机监控指标包括但不限于以下几种:
- 机器负载(Load)
- CPU使用率
- 内存使用率,包括空闲内存(Free Memory)和已使用内存(Used Memory)
- 磁盘I/O使用率,包括读使用率和写使用率
- 网络I/O使用率
- TCP连接数
- 打开文件数
- inode使用情况
考虑到我们并不是要系统地学习调优与监控主机性能,因此我并不打算对上面的每一个指标都进行详细解释,我重点分享一下机器负载和CPU使用率的监控方法。我会以Linux平台为例来进行说明,其他平台应该也是类似的。
首先,我们来看一张图片。我在Kafka集群的某台Broker所在的主机上运行top命令,输出的内容如下图所示:
在图片的右上角,我们可以看到load average的3个值:4.85,2.76和1.26,它们分别代表过去1分钟、过去5分钟和过去15分钟的Load平均值。在这个例子中,我的主机总共有4个CPU核,但Load值却达到了4.85,这就说明,一定有进程暂时“抢不到”任何CPU资源。同时,Load值一直在增加,也说明这台主机上的负载越来越大。
举这个例子,其实我真正想说的是CPU使用率。很多人把top命令中“%CPU”列的输出值当作CPU使用率。比如,在上面这张图中,PID为2637的Java进程是Broker进程,它对应的“%CPU”的值是102.3。你不要认为这是CPU的真实使用率,这列值的真实含义是进程使用的所有CPU的平均使用率,只是top命令在显示的时候转换成了单个CPU。因此,如果是在多核的主机上,这个值就可能会超过100。在这个例子中,我的主机有4个CPU核,总CPU使用率是102.3,那么,平均每个CPU的使用率大致是25%。
JVM监控
除了主机监控之外,另一个重要的监控维度就是JVM监控。Kafka Broker进程是一个普通的Java进程,所有关于JVM的监控手段在这里都是适用的。
监控JVM进程主要是为了让你全面地了解你的应用程序(Know Your Application)。具体到Kafka而言,就是全面了解Broker进程。比如,Broker进程的堆大小(HeapSize)是多少、各自的新生代和老年代是多大?用的是什么GC回收器?这些监控指标和配置参数林林总总,通常你都不必全部重点关注,但你至少要搞清楚Broker端JVM进程的Minor GC和Full GC的发生频率和时长、活跃对象的总大小和JVM上应用线程的大致总数,因为这些数据都是你日后调优Kafka Broker的重要依据。
我举个简单的例子。假设一台主机上运行的Broker进程在经历了一次Full GC之后,堆上存活的活跃对象大小是700MB,那么在实际场景中,你几乎可以安全地将老年代堆大小设置成该数值的1.5倍或2倍,即大约1.4GB。不要小看700MB这个数字,它是我们设定Broker堆大小的重要依据!
很多人会有这样的疑问:我应该怎么设置Broker端的堆大小呢?其实,这就是最合理的评估方法。试想一下,如果你的Broker在Full GC之后存活了700MB的数据,而你设置了堆大小为16GB,这样合理吗?对一个16GB大的堆执行一次GC要花多长时间啊?!
因此,我们来总结一下。要做到JVM进程监控,有3个指标需要你时刻关注:
- Full GC发生频率和时长。这个指标帮助你评估Full GC对Broker进程的影响。长时间的停顿会令Broker端抛出各种超时异常。
- 活跃对象大小。这个指标是你设定堆大小的重要依据,同时它还能帮助你细粒度地调优JVM各个代的堆大小。
- 应用线程总数。这个指标帮助你了解Broker进程对CPU的使用情况。
总之,你对Broker进程了解得越透彻,你所做的JVM调优就越有效果。
谈到具体的监控,前两个都可以通过GC日志来查看。比如,下面的这段GC日志就说明了GC后堆上的存活对象大小。
2019-07-30T09:13:03.809+0800: 552.982: [GC cleanup 827M->645M(1024M), 0.0019078 secs]
这个Broker JVM进程默认使用了G1的GC算法,当cleanup步骤结束后,堆上活跃对象大小从827MB缩减成645MB。另外,你可以根据前面的时间戳来计算每次GC的间隔和频率。
自0.9.0.0版本起,社区将默认的GC收集器设置为G1,而G1中的Full GC是由单线程执行的,速度非常慢。因此,你一定要监控你的Broker GC日志,即以kafkaServer-gc.log开头的文件。注意不要出现Full GC的字样。一旦你发现Broker进程频繁Full GC,可以开启G1的-XX:+PrintAdaptiveSizePolicy开关,让JVM告诉你到底是谁引发了Full GC。
集群监控
说完了主机和JVM监控,现在我来给出监控Kafka集群的几个方法。
1.查看Broker进程是否启动,端口是否建立。
千万不要小看这一点。在很多容器化的Kafka环境中,比如使用Docker启动Kafka Broker时,容器虽然成功启动了,但是里面的网络设置如果配置有误,就可能会出现进程已经启动但端口未成功建立监听的情形。因此,你一定要同时检查这两点,确保服务正常运行。
2.查看Broker端关键日志。
这里的关键日志,主要涉及Broker端服务器日志server.log,控制器日志controller.log以及主题分区状态变更日志state-change.log。其中,server.log是最重要的,你最好时刻对它保持关注。很多Broker端的严重错误都会在这个文件中被展示出来。因此,如果你的Kafka集群出现了故障,你要第一时间去查看对应的server.log,寻找和定位故障原因。
3.查看Broker端关键线程的运行状态。
这些关键线程的意外挂掉,往往无声无息,但是却影响巨大。比方说,Broker后台有个专属的线程执行Log Compaction操作,由于源代码的Bug,这个线程有时会无缘无故地“死掉”,社区中很多Jira都曾报出过这个问题。当这个线程挂掉之后,作为用户的你不会得到任何通知,Kafka集群依然会正常运转,只是所有的Compaction操作都不能继续了,这会导致Kafka内部的位移主题所占用的磁盘空间越来越大。因此,我们有必要对这些关键线程的状态进行监控。
可是,一个Kafka Broker进程会启动十几个甚至是几十个线程,我们不可能对每个线程都做到实时监控。所以,我跟你分享一下我认为最重要的两类线程。在实际生产环境中,监控这两类线程的运行情况是非常有必要的。
- Log Compaction线程,这类线程是以kafka-log-cleaner-thread开头的。就像前面提到的,此线程是做日志Compaction的。一旦它挂掉了,所有Compaction操作都会中断,但用户对此通常是无感知的。
- 副本拉取消息的线程,通常以ReplicaFetcherThread开头。这类线程执行Follower副本向Leader副本拉取消息的逻辑。如果它们挂掉了,系统会表现为对应的Follower副本不再从Leader副本拉取消息,因而Follower副本的Lag会越来越大。
不论你是使用jstack命令,还是其他的监控框架,我建议你时刻关注Broker进程中这两类线程的运行状态。一旦发现它们状态有变,就立即查看对应的Kafka日志,定位原因,因为这通常都预示会发生较为严重的错误。
4.查看Broker端的关键JMX指标。
Kafka提供了超多的JMX指标供用户实时监测,我来介绍几个比较重要的Broker端JMX指标:
- BytesIn/BytesOut:即Broker端每秒入站和出站字节数。你要确保这组值不要接近你的网络带宽,否则这通常都表示网卡已被“打满”,很容易出现网络丢包的情形。
- NetworkProcessorAvgIdlePercent:即网络线程池线程平均的空闲比例。通常来说,你应该确保这个JMX值长期大于30%。如果小于这个值,就表明你的网络线程池非常繁忙,你需要通过增加网络线程数或将负载转移给其他服务器的方式,来给该Broker减负。
- RequestHandlerAvgIdlePercent:即I/O线程池线程平均的空闲比例。同样地,如果该值长期小于30%,你需要调整I/O线程池的数量,或者减少Broker端的负载。
- UnderReplicatedPartitions:即未充分备份的分区数。所谓未充分备份,是指并非所有的Follower副本都和Leader副本保持同步。一旦出现了这种情况,通常都表明该分区有可能会出现数据丢失。因此,这是一个非常重要的JMX指标。
- ISRShrink/ISRExpand:即ISR收缩和扩容的频次指标。如果你的环境中出现ISR中副本频繁进出的情形,那么这组值一定是很高的。这时,你要诊断下副本频繁进出ISR的原因,并采取适当的措施。
- ActiveControllerCount:即当前处于激活状态的控制器的数量。正常情况下,Controller所在Broker上的这个JMX指标值应该是1,其他Broker上的这个值是0。如果你发现存在多台Broker上该值都是1的情况,一定要赶快处理,处理方式主要是查看网络连通性。这种情况通常表明集群出现了脑裂。脑裂问题是非常严重的分布式故障,Kafka目前依托ZooKeeper来防止脑裂。但一旦出现脑裂,Kafka是无法保证正常工作的。
其实,Broker端还有很多很多JMX指标,除了上面这些重要指标,你还可以根据自己业务的需要,去官网查看其他JMX指标,把它们集成进你的监控框架。
5.监控Kafka客户端。
客户端程序的性能同样需要我们密切关注。不管是生产者还是消费者,我们首先要关心的是客户端所在的机器与Kafka Broker机器之间的网络往返时延(Round-Trip Time,RTT)。通俗点说,就是你要在客户端机器上ping一下Broker主机IP,看看RTT是多少。
我曾经服务过一个客户,他的Kafka生产者TPS特别低。我登到机器上一看,发现RTT是1秒。在这种情况下,无论你怎么调优Kafka参数,效果都不会太明显,降低网络时延反而是最直接有效的办法。
除了RTT,客户端程序也有非常关键的线程需要你时刻关注。对于生产者而言,有一个以kafka-producer-network-thread开头的线程是你要实时监控的。它是负责实际消息发送的线程。一旦它挂掉了,Producer将无法正常工作,但你的Producer进程不会自动挂掉,因此你有可能感知不到。对于消费者而言,心跳线程事关Rebalance,也是必须要监控的一个线程。它的名字以kafka-coordinator-heartbeat-thread开头。
除此之外,客户端有一些很重要的JMX指标,可以实时告诉你它们的运行情况。
从Producer角度,你需要关注的JMX指标是request-latency,即消息生产请求的延时。这个JMX最直接地表征了Producer程序的TPS;而从Consumer角度来说,records-lag和records-lead是两个重要的JMX指标。我们在专栏第22讲解释过这两个指标的含义,这里我就不再赘述了。总之,它们直接反映了Consumer的消费进度。如果你使用了Consumer Group,那么有两个额外的JMX指标需要你关注下,一个是join rate,另一个是sync rate。它们说明了Rebalance的频繁程度。如果在你的环境中,它们的值很高,那么你就需要思考下Rebalance频繁发生的原因了。
小结
好了,我们来小结一下。今天,我介绍了监控Kafka的方方面面。除了监控Kafka集群,我还推荐你从主机和JVM的维度进行监控。对主机的监控,往往是我们定位和发现问题的第一步。JVM监控同样重要。要知道,很多Java进程碰到的性能问题是无法通过调整Kafka参数是解决的。最后,我罗列了一些比较重要的Kafka JMX指标。在下一讲中,我会专门介绍一下如何使用各种工具来查看这些JMX指标。
开放讨论
请分享一下你在监控Kafka方面的心得,以及你的运维技巧。
欢迎写下你的思考和答案,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。
- 我已经设置了昵称 👍(16) 💬(1)
要怎么看到JMX指标呢,能否讲下
2019-09-04 - r 👍(9) 💬(1)
老师总结的真好。我有个疑问,没找到相关资料做支撑。就是一套kafka集群,最多能容纳多少个topic-partition,这个是集群规模有关吗,
2019-08-24 - ykkk88 👍(6) 💬(2)
有什么好的开源的监控工具么
2019-08-25 - 快跑 👍(3) 💬(1)
请教老师一下 从监控上能看到读取kafka数据是从页缓存还是磁盘么,对应的指标有哪些?
2020-03-14 - frenco 👍(3) 💬(2)
老师好, 请教个问题: 按您之前有个推荐的配置kafka内存的说法,一般堆内存配置6G就好了。 那新生代和老年代默认2:1 分配。 如果只需要6G的内存, 我们生产的机器一般都是64G以上内存, 那机器是不是有很大浪费呢。
2019-11-08 - Geek_cd6rkj 👍(3) 💬(2)
请教下老师,我们最近遇到一个监控问题,监控各个topic的消息堆积,发现如果业务方由于服务下线,不使用某个consume group了,结果这个group的消息堆积会一直增加,运维就会收到监控告警,但是运维并不好判断哪个group已经不使用了,这个能有什么自动化的手段吗
2019-08-29 - wxr 👍(3) 💬(6)
怎样比较好的监控消费延时呢
2019-08-24 - 风中花 👍(2) 💬(1)
老师你的公众号怎么找到呢
2019-11-30 - Geek_72a3d3 👍(2) 💬(4)
“同时,Load 值一直在增加,也说明这台主机上的负载越来越大。” 老师,您好,Load值好像是越来越小。??
2019-09-17 - 外星人 👍(2) 💬(1)
你好,单个topic可以支撑的最多partition个数多少啊?我们生产上有个topic超级大,占了整个集群的一半以上的流量,这种情况是需要拆分吗?
2019-08-24 - 张亮 👍(1) 💬(1)
Kafka监控是一个非常专业和体系化的事情,Elasticearch基本将系统指标、JVM指标作为Metric上报出来自闭环非常方便实用,在开源Logi-KafkaManager的时候,我一直计划将这些指标通过JMX直接暴露出来,你怎么看?
2021-02-15 - 你为啥那么牛 👍(1) 💬(1)
这应该是最有水平的一篇文章了,经验值超高
2021-02-07 - 夏日 👍(1) 💬(1)
ttl一般多少以内比较正常,比如在考虑在双活中心搭建一套kafka集群的时候,怎么判断不会由于节点之间的传输延时导致kafka性能不高?
2020-11-23 - 胡小禾 👍(1) 💬(1)
“如果group不使用了,它的状态就是nonactive了” 这个nonactive 在ZK上是不是有节点?
2020-05-28 - 追光者 👍(1) 💬(3)
老师,您好,想请教一个关于 Metricbeat 采集 kafka 数据的问题: 配置好 modules.d/kafka.yml 启动 metricbeat 采集不到数据,提示信息: 2019-08-29T16:13:33.827+0800 INFO kafka/log.go:53 kafka message: Successful SASL handshake 2019-08-29T16:13:33.828+0800 INFO kafka/log.go:53 SASL authentication successful with broker 10.162.7.2:9092:4 - [0 0 0 0] 2019-08-29T16:13:33.828+0800 INFO kafka/log.go:53 Connected to broker at 10.162.7.2:9092 (unregistered) 2019-08-29T16:13:33.832+0800 INFO kafka/log.go:53 Closed connection to broker 10.162.7.2:9092 system 的可以采集到,请问这是什么原因呀 配置文件: - module: kafka metricsets: - partition - consumergroup period: 10s hosts: ["10.162.3.90:9092"] client_id: xl retries: 3 backoff: 250ms topics: [] username: "admin" password: "admin"
2019-08-30