1、背景
最近在折腾Kafka日志集群,由于公司部署的应用不断增加,日志采集程序将采集到的日志发送到Kafka集群时出现了较大延迟,总的TPS始终上不去,为了不影响业务团队通过日志排查问题,采取了先解决问题,再排查的做法,对Kafka集群进行扩容,但扩容后尴尬的是新增加的5台机器中,有两台机器的消费发送响应时间比其他机器明显高出不少,为了确保消息服务的稳定性,又临时对集群进行缩容,将这台机器从集群中剔除, 具体的操作就是简单粗暴的使用 kill pid命令 ,但意外发生了。
发现Java客户端报如下错误:
而Go客户端报的错误如下所示:
基本可以认为是部分分区没有在线Leader,无法成功发送消息。
2、问题分析
那为什么会出现这个问题吗?Kafka一个节点下线,不是会自动触发故障转移,分区leader不是会被重新选举吗?请带着这个疑问,开始我们今天的探究之旅。
首先我们可以先看看当前存在问题的分区的路由信息,从第一张图中看出主题dw_test_kafka_0816000的101分区消息发送失败,我们在Zookeeper中看一下其状态,具体命令如下:
./zkCli.sh -server 127.0.0.1:2181
get -s /kafka_cluster_01/brokers/topics/dw_test_kafka_0816000/partitions/101/state
该命令可以看到对应分区的相信信息,如下图所示:
这里显示出leader的状态为-1,而isr列表中只有一副本,在broker-1上,但此时broker id为1的机器已经下线了,那为什么不会触发分区Leader重新选举呢?
其实看到这里,我相信你只要稍微细想一下,就能发现端倪,isr字段的值为1,说明该分区的副本数为1,说明该分区只在一个Broker上存储数据,一旦Broker下线,由于集群内其他Broker上并没有该分区的数据,此时是无法进行故障转移的,因为一旦要进行故障转移,分区的数据就会丢失,这样带来的影响将是非常严重的。
那为什么该主题的副本数会设置为1呢?那是因为当时集群的压力太大,节点之间复制数据量巨大,网卡基本满负荷在运转,而又是日志集群,对数据的丢失的接受程度较大,故当时为了避免数据在集群之间的大量复制,将该主题的副本数设置为了1。
但集群节点的停机维护是少不了的,总不能每一次停机维护,都会出现一段时间数据写入失败吧。要解决这个问题,我们在停机之前,需要先对主题进行分区移动,将该主题的分区从需要停机的集群中移除。
主题分区移动的具体做法,请参考我之前的一篇文章Kafka主题迁移实践 的第三部分。