Log管理机制

Log管理机制

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

1 前言

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

 

 

2 Kakfa的日志格式

2.1Partition的数据文件

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

 

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

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

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

 

 

在V1版本中,kakfa的消息格式以下图所示:服务器

 

 

V2版本并发

 

 

具体能够参考下文app

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

 

2.2 Log的分段和索引

数据文件的分段.net

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

http://www.javashuo.com/article/p-goagrlby-bo.html

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/

http://www.javashuo.com/article/p-wvionlqd-b.html

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

http://www.javashuo.com/article/p-cafkmorp-cc.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

相关文章
相关标签/搜索