线上的Kafka运行一段时间后,随着topic, partition越来越多,会发现一个现象:有的时候需要做一些运维变更,重启起来特别慢。
于是就像分析一下Kafka启动时间主要消耗在哪里,看看有没有调优空间。
就从KafkaServer的startup方法入手分析:
initZk
主要是连接Zookeeper, 然后在Zookeeper上初始化Kafka需要的一些永久节点。这里有个注意的是,如果我们有多套Kafka集群,我们是可以公用一套Zookeeper集群的,而没有必要每个Kafka集群私自搭建一套Zookeeper,但是Kafka默认是将这些永久节点创建在Zookeeper的根路径,所以如果要公用Zookeeper那最好就将不同的Kafka集群放到不同的路径下。配置如下:
zookeeper.connect=127.0.0.1:2181/kafka1,Kafka启动的时候就会将自己的永久节点创建在/kafka1下面。
不过按照这种方式的配置有多一步连接Zookeeper和判断/kafka1节点是否存在的开销,这个时间理论上不会很长。
init logManager
对于运行一段时间的集群,这一步是启动时最耗时的。主要时间消耗在LogManager里的loadLogs。这里会把所有的日志目录打开,然后“处理”每个partition里的每个LogSegment。
这里简单的描述一下Kafka的目录结构:Kafka通过log.dirs可以配置多个日志目录,比如你有多块磁盘,那么就可以将日志分散到这些磁盘里。然后每个目录下就是partition的目录,目录名称为 topic-partition id,比如 __consumer_offsets-12,那就是topic是__consumer_offsets,partition是12。然后在parition目录就有两类文件,以.log为后缀的消息内容的文件,以.index为后缀的逻辑offset到物理offset的映射文件。这些.log, .index文件的文件名也挺有意思,名称都是用逻辑offset来命名的,比如00000000000000000100.log。
在loadLogs里针对log.dirs里的每个目录都会开一个线程池来进行处理,这个线程池的线程数是由num.recovery.threads.per.data.dir这个配置来控制的,这个配置值默认是1,而且这个线程池仅仅是在启动的时候使用,所以即使配的很大也不会影响之后的Kafka的运行。所以这个值是影响启动很重要的因素。我们有个集群,有12个目录,然后将这个参数修改为2,也就是总共有24个线程来处理,Kafka的启动时间从5分钟降低到了2分钟。
再来看看处理过程中主要干了些啥呢,初始化Log,然后就是loadSegments。
打开一个个的LogSegment。这里有点要注意的是,Kafka启动的时候会把日志目录所有存在的.log, .index都给打开。这个大部分时候没有什么问题,但是我们之前也碰到一个故障:Too many open files。打开完.log和.index,会做一个简单的index检查。
这个检查算是一个基本的检查,.index文件里每一项是8个字节:4个字节的逻辑offset(real offset - baSEOffset),4个字节表示消息在.log文件中的物理offset。那么如果.index文件是完整的,则用文件的大小应该能整除8。这个检查如果没有通过的话,那么就会将.index文件删掉,然后进行重建,需要将.log文件进行一次遍历,这个时间就有点长了。另外,如果.log文件存在,而.index文件不存在也需要重建。
大部分时候这样loadLogs的工作就算完成了,但是如果你停止Kafka的时候是非正常关闭,那么就会带来非常大的工作量了。什么叫非正常关闭呢?Kafka会检查每个log dir目录是否有一个名为.kafka_cleanshutdown的文件,如果存在则是正常停止。这是什么意思?在Kafka正常停止的时候,会做一些保存和清理工作,然后创建这样一个文件,所以如果要做正常维护的时候千万不要直接Kill -9 Kafka的进程哦。
好了,剩下的工作基本上耗时不长,所以影响Kafka启动的工作主要是处理这些log文件,而其中num.recovery.threads.per.data.dir这个参数是唯一我们能提速的地方。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。