之所以写这篇文章,是因为之前面试的时候被面试官问(down)了。面试官说:“你说你熟悉Kafka?你看过源码了吗?那你说说怎么读写kafkalogsegments吧?”我心里默默的说,“卧槽……我说我看到一点点源码,不是一点点,我就知??道我不会提这句话的!”,怎么办,只能回家了并等待通知。但是为了以后抢回名额,我们不能每天坐以待毙,从一点点到十亿点。今天我们就从源码层面看一下如何读写Kafkalogsegments。Kafka的存储结构众所周知。Kafka的Topic可以有多个分区。分区实际上是最小的读取和存储结构。即Consumer看似订阅了一个Topic,但实际上是从Topic下的某个partition获取消息。生产者发送消息也是如此。Topic-分区关系上图展示了整体的逻辑关系,映射到磁盘上实际代码的关系如下图所示:每个分区对应一个Log对象,它是磁盘中的一个子目录,子目录会有多组日志段,即多个LogSegment,每组日志段包括:消息日志文件(以log结尾)、位移索引文件(以index结尾)、时间戳索引文件(以时间索引)。其实还有其他后缀的文件,比如.txnindex,.deleted等等。限于篇幅,暂且不提。下面是日志的定义。下面是日志段的定义。在内存中保留更多索引。对应Broker端参数log.index.interval.bytes值,默认为4KB。通过索引查找消息的实际过程是先通过偏移量找到索引所在的文件,然后通过二分法找到距离目标最近的索引,然后依次遍历消息文件找到目标文件.这个操作的时间复杂度是O(log2n)+O(m),其中n是索引文件中索引的个数,m是稀疏度。这就是空间和时间的交换,经过数据结构和算法的平衡,很精彩!再说rollJitterMs,它其实是一个扰动值,对应的参数是log.roll.jitter.ms,其实是指logSegment的分段,log.segment.bytes,这个参数控制logsegment文件的大小,默认为1G,即当文件存储超过1G时,新建一个文件写入。这个是按size维度的,另外一个参数是log.segment.ms,按时间分段。配置完这个参数后,如果分区很多很多,而且因为这个参数是全局的,很多文件需要同时拆分,磁盘IO会承受不住,所以需要设置一个rollJitterMs转移他们。redis缓存的过期时间怎么办?在过期时间上加一个随机数,防止大量缓存同时过期导致缓存打垮数据库。看看知识都是连在一起的!写入日志段1.判断当前日志段是否为空。如果为空,记录时间作为后续日志段的依据。2.保证位移值合法,最后调用的是AbstractIndex.toRelative(..)方法,即使判断偏移量是小于0还是大于int的最大值。3.append消息其实就是通过FileChannel写入消息。当然,它只是写入内存和页面缓存。是否刷盘取决于配置。4.更新日志段的最大时间戳和最大时间戳对应的位移值。这个时间戳实际上是作为定期删除日志的依据。5.如有必要,更新索引条目(bytesSinceLastIndexEntry>indexIntervalBytes)。最后将流程图消息写入到流程日志段读取1。根据第一条消息的偏移量,通过OffsetIndex找到对应消息的物理位置和大小。2、获取LogOffsetMetadata,其中包括消息的偏移量、消息所在段的初始偏移量、物理位置3、判断minOneMessage是否为真,如果为真,调整返回一个消息大小。其实就是当单条消息大于maxSize时才可以返回,防止消费者挨饿4.然后计算最大fetchSize,即(最大物理位移-这条消息的初始物理位移)和最小值adjustedMaxSize的(这一波我不是很理解,因为上一波的操作adjustedMaxSize已经是最小的了是一条消息的大小)5.调用FileRecords的slice方法从中读取指定大小的消息集合指定位置,并构造FetchDataInfo返回,然后得出一个流程图:消息读取过程总结,从哪里跌倒到哪里爬起来,对吧?经过这波操作,下次就不怕问面试官了。源码平平无奇,哈哈哈哈(先要有冲劲)其实这只是Kafka源码的冰山一角,任重而道远。虽然KafkaBroker是用Scala写的,但是语言不是问题。看着不难,评论也很丰富。如果遇到不懂的语法,就去查查。所以,强烈建议大家从源码入手,从源码上理解。今天说的append和read是很核心的功能,但是乍一看并不复杂,大家不要被源码这个词吓到了。看源码可以让我们深入理解内部的设计原理,提高自己的代码水平(我经常看,我还能这么写)。当然还有系统架构能力。而对我来说最重要的是会假装(哈哈哈)。情景剧中的老白盯着监控大屏,“为什么?为什么KafkaBroker的物理磁盘I/O负载突然这么高?”。几根头发立在老白的头上,一副无奈的样子。“你设置了log.segment.ms参数了吗?试试log.roll.jitter.ms。”等老白一抬头,我已经走出了办公室,只剩下伟岸的背影和闪闪发亮的光头!“我变秃了,变强了”
