gitbook/Kafka核心技术与实战/docs/126109.md
2022-09-03 22:05:03 +08:00

119 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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命令输出的内容如下图所示
![](https://static001.geekbang.org/resource/image/00/e0/00f0ead463b17e667d09b6cea4e42de0.png)
在图片的右上角我们可以看到load average的3个值4.852.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个指标需要你时刻关注
1. Full GC发生频率和时长。这个指标帮助你评估Full GC对Broker进程的影响。长时间的停顿会令Broker端抛出各种超时异常。
2. 活跃对象大小。这个指标是你设定堆大小的重要依据同时它还能帮助你细粒度地调优JVM各个代的堆大小。
3. 应用线程总数。这个指标帮助你了解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 TimeRTT。通俗点说就是你要在客户端机器上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讲](https://time.geekbang.org/column/article/109238)解释过这两个指标的含义这里我就不再赘述了。总之它们直接反映了Consumer的消费进度。如果你使用了Consumer Group那么有两个额外的JMX指标需要你关注下一个是join rate另一个是sync rate。它们说明了Rebalance的频繁程度。如果在你的环境中它们的值很高那么你就需要思考下Rebalance频繁发生的原因了。
## 小结
好了我们来小结一下。今天我介绍了监控Kafka的方方面面。除了监控Kafka集群我还推荐你从主机和JVM的维度进行监控。对主机的监控往往是我们定位和发现问题的第一步。JVM监控同样重要。要知道很多Java进程碰到的性能问题是无法通过调整Kafka参数是解决的。最后我罗列了一些比较重要的Kafka JMX指标。在下一讲中我会专门介绍一下如何使用各种工具来查看这些JMX指标。
![](https://static001.geekbang.org/resource/image/28/93/28e6d8c2459b5d123f443173ac122c93.jpg)
## 开放讨论
请分享一下你在监控Kafka方面的心得以及你的运维技巧。
欢迎写下你的思考和答案,我们一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。