一次面试引发的Kafka源码之旅

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 一次面试引发的Kafka源码之旅

引子


之所以写这篇文章是因为之前面试时候被面试官问到(倒)了,面试官说:“你说你对Kafka比较熟?看过源码? 那说说kafka日志段如何读写的吧?”

我心里默默的说了句 “擦...我说看过一点点源码,不是亿点点。早知道不提这句了!”,那怎么办呢,只能回家等通知了啊。


image.png

但是为了以后找回场子,咱也不能坐以待毙,日拱一卒从一点点到亿点点。今天我们就来看看源码层面来Kafka日志段的是如何读写的。


Kafka的存储结构


总所周知,Kafka的Topic可以有多个分区,分区其实就是最小的读取和存储结构,即Consumer看似订阅的是Topic,实则是从Topic下的某个分区获得消息,Producer也是发送消息也是如此。

image.png

上图是总体逻辑上的关系,映射到实际代码中在磁盘上的关系则是如下图所示:

image.png

每个分区对应一个Log对象,在磁盘中就是一个子目录,子目录下面会有多组日志段即多Log Segment,每组日志段包含:消息日志文件(以log结尾)、位移索引文件(以index结尾)、时间戳索引文件(以timeindex结尾)。其实还有其它后缀的文件,例如.txnindex、.deleted等等。篇幅有限,暂不提起。


以下为日志的定义

image.png


以下为日志段的定义

image.png


indexIntervalBytes可以理解为插了多少消息之后再建一个索引,由此可以看出Kafka的索引其实是稀疏索引,这样可以避免索引文件占用过多的内存,从而可以在内存中保存更多的索引。对应的就是Broker 端参数log.index.interval.bytes 值,默认4KB。


实际的通过索引查找消息过程是先通过offset找到索引所在的文件,然后通过二分法找到离目标最近的索引,再顺序遍历消息文件找到目标文件。这波操作时间复杂度为O(log2n)+O(m),n是索引文件里索引的个数,m为稀疏程度。


这就是空间和时间的互换,又经过数据结构与算法的平衡,妙啊!


再说下rollJitterMs,这其实是个扰动值,对应的参数是log.roll.jitter.ms,这其实就要说到日志段的切分了,log.segment.bytes,这个参数控制着日志段文件的大小,默认是1G,即当文件存储超过1G之后就新起一个文件写入。这是以大小为维度的,还有一个参数是log.segment.ms,以时间为维度切分。


那配置了这个参数之后如果有很多很多分区,然后因为这个参数是全局的,因此同一时刻需要做很多文件的切分,这磁盘IO就顶不住了啊,因此需要设置个rollJitterMs,来岔开它们。


怎么样有没有联想到redis缓存的过期时间?过期时间加个随机数,防止同一时刻大量缓存过期导致缓存击穿数据库。 看看知识都是通的啊!


日志段的写入


image.png

1、判断下当前日志段是否为空,空的话记录下时间,来作为之后日志段的切分依据

2、确保位移值合法,最终调用的是AbstractIndex.toRelative(..)方法,即使判断offset是否小于0,是否大于int最大值。

3、append消息,实际上就是通过FileChannel将消息写入,当然只是写入内存中及页缓存,是否刷盘看配置。

4、更新日志段最大时间戳和最大时间戳对应的位移值。这个时间戳其实用来作为定期删除日志的依据

5、更新索引项,如果需要的话(bytesSinceLastIndexEntry > indexIntervalBytes)

最后再来个流程图


image.png


日志段的读取


image.png

1、根据第一条消息的offset,通过OffsetIndex找到对应的消息所在的物理位置和大小。

2、获取LogOffsetMetadata,元数据包含消息的offset、消息所在segment的起始offset和物理位置

3、判断minOneMessage是否为true,若是则调整为必定返回一条消息大小,其实就是在单条消息大于maxSize的情况下得以返回,防止消费者饿死

4、再计算最大的fetchSize,即(最大物理位移-此消息起始物理位移)和adjustedMaxSize的最小值(这波我不是很懂,因为以上一波操作adjustedMaxSize已经最小为一条消息的大小了)

5、调用 FileRecordsslice 方法从指定位置读取指定大小的消息集合,并且构造FetchDataInfo返回

再来个流程图:


image.png


小结


从哪里跌倒就从哪里爬起来对吧,这波操作下来咱也不怕下次遇到面试官问了。

区区源码不过尔尔,哈哈哈哈(首先得要有气势)

实际上这只是Kafka源码的冰山一角,长路漫漫。虽说Kafka Broker都是由Scala写的,不过语言不是问题,这不看下来也没什么难点,注释也很丰富。遇到不知道的语法小查一下搞定。

所以强烈建议大家入手源码,从源码上理解。今天说的 appendread 是很核心的功能,但一看也并不复杂,所以不要被源码这两个字吓到了。

看源码可以让我们升入的理解内部的设计原理,精进我们的代码功力(经常看着看着,我擦还能这么写)。当然还有系统架构能力。

然后对我而言最重要的是可以装逼了(哈哈哈)。


情景剧


老白正目不转睛盯着监控大屏,“为什么?为什么Kafka Broker物理磁盘 I/O 负载突然这么高?”。寥寥无几的秀发矗立在老白的头上,显得如此的无助。

“是不是设置了 log.segment.ms参数 ? 试试 log.roll.jitter.ms吧”,老白抬头间我已走出了办公室,留下了一个伟岸的背影和一颗锃亮的光头!

“我变秃了,也变强了”


相关文章
|
1月前
|
消息中间件 运维 Java
招行面试:RocketMQ、Kafka、RabbitMQ,如何选型?
45岁资深架构师尼恩针对一线互联网企业面试题,特别是招商银行的高阶Java后端面试题,进行了系统化梳理。本文重点讲解如何根据应用场景选择合适的消息中间件(如RabbitMQ、RocketMQ和Kafka),并对比三者的性能、功能、可靠性和运维复杂度,帮助求职者在面试中充分展示技术实力,实现“offer直提”。此外,尼恩还提供了《尼恩Java面试宝典PDF》等资源,助力求职者提升架构、设计、开发水平,应对高并发、分布式系统的挑战。更多内容及技术圣经系列PDF,请关注【技术自由圈】获取。
|
2月前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
2月前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
74 2
|
3月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
133 2
|
3月前
|
消息中间件 大数据 Kafka
大厂面试高频:Kafka、RocketMQ、RabbitMQ 的优劣势比较
本文深入探讨了消息队列的核心概念、应用场景及Kafka、RocketMQ、RabbitMQ的优劣势比较,大厂面试高频,必知必会,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:Kafka、RocketMQ、RabbitMQ 的优劣势比较
|
3月前
|
消息中间件 存储 缓存
大厂面试高频:Kafka 工作原理 ( 详细图解 )
本文详细解析了 Kafka 的核心架构和实现原理,消息中间件是亿级互联网架构的基石,大厂面试高频,非常重要,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:Kafka 工作原理 ( 详细图解 )
|
4月前
|
消息中间件 存储 缓存
美团面试: Kafka为啥能实现 10Wtps 到100Wtps ?kafka 如何实现零复制 Zero-copy?
40岁老架构师尼恩分享了Kafka如何实现高性能的秘诀,包括零拷贝技术和顺序写。Kafka采用mmap和sendfile两种零拷贝技术,前者用于读写索引文件,后者用于向消费者发送消息,减少数据在用户空间和内核空间间的拷贝次数,提高数据传输效率。此外,Kafka通过顺序写日志文件,避免了磁盘寻道和旋转延迟,进一步提升了写入性能。尼恩还提供了系列技术文章和PDF资料,帮助读者深入理解这些技术,提升面试竞争力。
美团面试: Kafka为啥能实现 10Wtps 到100Wtps ?kafka 如何实现零复制 Zero-copy?
|
4月前
|
消息中间件 存储 Kafka
面试题:Kafka如何保证高可用?有图有真相
面试题:Kafka如何保证高可用?有图有真相
138 0
|
5月前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
532 37
|
6月前
|
消息中间件 算法 Java
面试官:Kafka中的key有什么用?
面试官:Kafka中的key有什么用?
235 3
面试官:Kafka中的key有什么用?