线上的Kafka运行一段时间后,随着topic, partition越来越多,会发现一个现象:有的时候需要做一些运维变更,重启起来特别慢。

于是就像分析一下Kafka启动时间主要消耗在哪里,看看有没有调优空间。

就从KafkaServer的startup方法入手分析:

  1. 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。

  1. 删除后缀名为.deleted, .cleaned的文件

  2. 如果.index对应的.log文件不存在则将.index删除

  3. 打开一个个的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文件不存在也需要重建。

  4. 大部分时候这样loadLogs的工作就算完成了,但是如果你停止Kafka的时候是非正常关闭,那么就会带来非常大的工作量了。什么叫非正常关闭呢?Kafka会检查每个log dir目录是否有一个名为.kafka_cleanshutdown的文件,如果存在则是正常停止。这是什么意思?在Kafka正常停止的时候,会做一些保存和清理工作,然后创建这样一个文件,所以如果要做正常维护的时候千万不要直接Kill -9 Kafka的进程哦。

好了,剩下的工作基本上耗时不长,所以影响Kafka启动的工作主要是处理这些log文件,而其中num.recovery.threads.per.data.dir这个参数是唯一我们能提速的地方。


©著作权归作者所有:来自51CTO博客作者viphyy的原创作品,如需转载,请注明出处,否则将追究法律责任

好知识,才能预见未来

赞赏

0人进行了赞赏支持

更多相关文章

  1. Linux基础-18day-Linux系统磁盘管理(du/df/mount命令)
  2. 记一次服务器负载过高的排查过程
  3. Java文件上传是如何实现的?
  4. Composer常用指令、安装组件、自动加载器使用方式与更新方法
  5. PHP迷你MVC小框架实现步骤
  6. 运维少年系列 - python and cisco(2)
  7. 运维少年系列 - ansible and cisco(1)
  8. Linux轻量级监控软件-nmon
  9. 学习Clickhouse_目录

随机推荐

  1. Android之判断时间是否为今天
  2. android开源项目
  3. 移动互联
  4. Android(安卓)3.0 r1中文API文档(103) —
  5. Android中通过浏览器打开一个网页
  6. 把android平板USB上输出LOG方法
  7. android和js之间的简单交互
  8. android统计图绘制
  9. Android(安卓)listview下拉刷新 上拉加载
  10. Android按键消息传播流程