Log管理机制

Log管理机制

Kafka的消息在broker上都是以log的形式进行储存管理的,本篇主要介绍log的管理,包括log结构、创建、读写、分段、清理等。

1 前言

Kafka中的Message是以topic为基本单位组织的,不同的topic之间是相互独立的。每个partition存储一部分Message。引用官方的一张图,可以直观地看到topic和partition的关系。

 

2 Kakfa的日志格式

2.1Partition的数据文件

Partition中的每条Message由offset来表示它在这个partition中的偏移量,这个offset不是该Message在partition数据文件中的实际存储位置,而是逻辑上一个值,它唯一确定了partition中的一条Message。因此,可以认为offset是partition中Message的id。partition中的每条Message包含了以下三个属性:

  • l  offset
  • l  MessageSize
  • l  Record
  • l  其中offset为long型,MessageSize为int32,表示Record中data

有多大,data为message的具体内容。

在v0版本中,kafka的消息格式如下图所示:

 

在V1版本中,kakfa的消息格式如下图所示:

 

V2版本

 

具体可以参考下文

http://www.uml.org.cn/bigdata/2018051731.asp

2.2 Log的分段和索引

数据文件的分段

Kafka解决查询效率的手段之一是将数据文件分段,比如有100条Message,它们的offset是从0到99。假设将数据文件分成5段,第一段为0-19,第二段为20-39,以此类推,每段放在一个单独的数据文件里面,数据文件以该段中最小的offset命名。这样在查找指定offset的Message的时候,用二分查找就可以定位到该Message在哪个段中。

为数据文件建索引

数据文件分段使得可以在一个较小的数据文件中查找对应offset的Message了,但是这依然需要顺序扫描才能找到对应offset的Message。为了进一步提高查找的效率,Kafka为每个分段后的数据文件建立了索引文件,文件名与数据文件的名字是一样的,只是文件扩展名为.index。

索引文件中包含若干个索引条目,每个条目表示数据文件中一条Message的索引。索引包含两个部分(均为4个字节的数字),分别为相对offset和position。

相对offset:因为数据文件分段以后,每个数据文件的起始offset不为0,相对offset表示这条Message相对于其所属数据文件中最小的offset的大小。举例,分段后的一个数据文件的offset是从20开始,那么offset为25的Message在index文件中的相对offset就是25-20 = 5。存储相对offset可以减小索引文件占用的空间。

position,表示该条Message在数据文件中的绝对位置。只要打开文件并移动文件指针到这个position就可以读取对应的Message了。

index文件中并没有为数据文件中的每条Message建立索引,而是采用了稀疏存储的方式,每隔一定字节的数据建立一条索引。这样避免了索引文件占用过多的空间,从而可以将索引文件保留在内存中。但缺点是没有建立索引的Message也不能一次定位到其在数据文件的位置,从而需要做一次顺序扫描,但是这次顺序扫描的范围就很小了。

2.3 log的逻辑结构

  • l  一个Partition Log由多个LogSegment组成
  • l  一个LogSegment代表了整个Partition Log中的某一段,它是由一个FileMessageSet和一个OffsetIndex组成
  • l  FileMessageSet:顾名思义,它代表了一个基于文件的消息集合。内部采用channel方式访问物理文件。
  • l  OffsetIndex:可以将其看做一个index table, 每一项代表了一个offset 与 物理文件(.log 文件)position的映射。此外它会与实际的物理文件(.index) 之间是建立的 mmap。
  • l  每一个Partition Log有一个nextOffsetMetadata 记录,用于记录下一个要添加的messageset的offset
  • l  每一个Log都有一个recoverypoint,用于记录真正flush到磁盘的消息的最后一个offset

2.4 log的物理结构

下面是一个kafka log dir下的文件分布:

 

1)一个Partition Log 对应于一个kafka broker 的log dir下面的一个分区目录。

2)一个LogSegment对应了partition log directoy下的两个文件:一个.log文件,一个.index文件。

 

3 kafka 的日志管理

在一个broker上的log都是通过LogManger来管理的,Kafka 的日志管理(LogManager)主要的作用是负责日志的创建、检索、清理,日志相关的读写操作实际上是由日志实例对象(Log)来处理的。

3.1 LogManger启动过程

LogManager 线程是在节点的 Kafka 服务启动时启动的,相关代码如下:

 

初始化 LogManger 主要有两个步骤:

  1. 创建指定的数据目录,并做相应的检查:
  • l  确保数据目录中没有重复的数据目录
  • l  数据目录不存在的话就创建相应的目录;
  • l  检查每个目录路径是否是可读的;
  1. 加载所有的日志分区,而每个日志也会加载该分区所有的 segment 文件,过程比较慢,所以 LogManager 使用线程池的方式,为每个日志的加载都会创建一个单独的线程。

虽然使用的是线程池提交任务,并发进行 load 分区日志,但这个任务本身是阻塞式的,只有当所有的分区日志加载完成,才能调用 startup() 启动 LogManager 线程。

KafkaServer 调用 startup() 方法启动 LogManager 线程,LogManager 启动后,后台会运行四个定时任务,代码实现如下:

 

四个后台定时线程的作用:

  • l  cleanupLogs:定时清理过期的日志 segment,并维护日志的大小(默认5min);
  • l  flushDirtyLogs:定时刷新将还没有写到磁盘上日志刷新到磁盘(默认 无限大);
  • l  checkpointRecoveryPointOffsets:定时将所有数据目录所有日志的检查点写到检查点文件中(默认 60s);
  • l  deleteLogs:定时删除标记为 delete 的日志文件(默认 30s)。

3.2 日志压缩

第一种:delete,即如果LogSegment到期了删除之,或者LogSegment+这次要添加的消息 > LogSegment的最大容量则删除最老的的LogSegment

第二种:compact,进行log压缩,也可以有效减少日志文件文件大小,缓解磁盘紧张情况。

在有些场景中,key和对应的value的值是不断变化的,就像数据库的记录一样,可以对同一条记录进行修改,在kafka中表现就是在某一时刻key=value1,可能在后续某一时刻,添加了一个key=value2的消息,如果消费者只关心最新的值,那么日志压缩就显得很有用,如下图所示:

 

  • l  # 如果启用日志压缩,并不会针对active log segment,即active log segment不会参加日志压缩,只是针对只读的log segment,避免active log segment成为热点,既要读写还要压缩
  • l  # 日志压缩的过程是通过多个cleaner线程来完成的,所以我们可以通过调整cleaner线程数来并发压缩性能,减少对整个服务器端的影响
  • l  # 一般情况下,Log数据量很大,为了避免cleaner线程和其他业务线程长时间竞争CPU,并不会将active log segment之外的其他可读LogSegment在一次压缩中全部处理掉,而是将这些LogSegment分批处理
  • l  每一个log都会被cleanercheckpoint分成clean和dirty2部分,如下图所示:

 

clean: 表示已经压缩的部分,压缩之后,offset是断断续续的,不是增量递增的

dirty: 表示未压缩部分,offset依然是连续递增的

  • l  # 每一个clean线程根据日志文件cleanableRatio值来优先压缩该值较效的log,也就说dirty占整个日志的比率越大优先级越高。
  • l  # clean线程在选定需要清理的log后,首先为dirty部分消息建立一个<key,key对应的last offset>的映射关系,该映射通过SkimpyOffsetMap维护,然后重新复制LogSegment,只保留SkimpyOffsetMap中记录的消息,抛弃掉其他消息
  • l  # 经过日志压缩后,日志文件和索引文件会不断减小,cleaner线程还会对相邻的LogSegmeng进行合并,避免出现过小的日志和索引文件

参考资料:

https://www.codetd.com/article/1652292

https://segmentfault.com/a/1190000005312891

https://blog.csdn.net/zhanglh046/article/details/72821483

https://blog.csdn.net/wl044090432/article/details/51008093

http://token01.com/2018/03/22/kafka%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%90(%E4%B8%89)%E4%B9%8B%E6%97%A5%E5%BF%97%E7%AE%A1%E7%90%86-LogManager/

https://blog.csdn.net/jewes/article/details/42970799

http://www.uml.org.cn/bigdata/2018051731.asp

https://www.cnblogs.com/devos/p/5100611.html

https://qinzhaokun.github.io/2017/09/10/Kafka%E8%AF%BB%E5%86%99%E5%8E%9F%E7%90%86%E4%B8%8E%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84/

---------------------

作者:happy19870612

来源:CSDN

原文:https://blog.csdn.net/zhanglh046/article/details/72821483

版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自www.cnblogs.com/zhy-heaven/p/10994046.html