尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
大数据技术之 Kafka (第 3 章 Kafka 架构深入 ) Log存储解析
Kafka 工作流程Kafka 中消息是以 topic 进行分类的生产者生产消息消费者消费消息都是面向 topic的。topic 是逻辑上的概念而 partition 是物理上的概念每个 partition 对应于一个 log 文件该 log 文件中存储的就是 producer 生产的数据。Producer 生产的数据会被不断追加到该log 文件末端且每条数据都有自己的 offset。消费者组中的每个消费者都会实时记录自己消费到了哪个 offset以便出错恢复时从上次的位置继续消费Kafka文件存储机制由于生产者生产的消息会不断追加到 log 文件末尾为防止 log 文件过大导致数据定位效率低下Kafka 采取了分片和索引机制将每个 partition 分为多个 segment。每个 segment对应两个文件——.index文件和.log文件。这些文件位于一个文件夹下该文件夹的命名规则为topic 名称分区序号。例如first 这个 topic 有三个分区则其对应的文件夹为 first-0,first-1,first-2。[rootbackup01 logs]# cd /usr/local/hadoop/kafka/kafka_2.12-2.4.1/logs/first-0 [rootbackup01 first-0]# ll total 8 -rw-r--r--. 1 root root 10485760 Mar 29 16:32 00000000000000000000.index -rw-r--r--. 1 root root 146 Mar 29 17:34 00000000000000000000.log -rw-r--r--. 1 root root 10485756 Mar 29 16:32 00000000000000000000.timeindex -rw-r--r--. 1 root root 8 Mar 29 16:32 leader-epoch-checkpoint [rootbackup01 first-0]#00000000000000000000.index 00000000000000000000.log 00000000000000170410.index 00000000000000170410.log 00000000000000239430.index 00000000000000239430.logindex 和 log 文件以当前 segment 的第一条消息的 offset 命名。下图为 index 文件和 log 文件的结构示意图.index文件存储大量的索引信息.log文件存储大量的数据索引文件中的元 数据指向对应数据文件中 message 的物理偏移地址。Kafka中的Message是以topic为基本单位组织的不同的topic之间是相互独立的。每个topic又可以分成几个不同的partition(每个topic有几个partition是在创建topic时指定的)每个partition存储一部分Message。借用官方的一张图可以直观地看到topic和partition的关系。partition是以文件的形式存储在文件系统中比如创建了一个名为page_visits的topic其有5个partition那么在Kafka的数据目录中(由配置文件中的log.dirs指定的)中就有这样5个目录: page_visits-0 page_visits-1page_visits-2page_visits-3page_visits-4其命名规则为topic_name-partition_id里面存储的分别就是这5个partition的数据。接下来本文将分析partition目录中的文件的存储格式和相关的代码所在的位置。Partition的数据文件Partition中的每条Message由offset来表示它在这个partition中的偏移量这个offset不是该Message在partition数据文件中的实际存储位置而是逻辑上一个值它唯一确定了partition中的一条Message。因此可以认为offset是partition中Message的id。partition中的每条Message包含了以下三个属性offsetMessageSizedata其中offset为long型MessageSize为int32表示data有多大data为message的具体内容。它的格式和Kafka通讯协议中介绍的MessageSet格式是一致。Partition的数据文件则包含了若干条上述格式的Message按offset由小到大排列在一起。它的实现类为FileMessageSet类图如下它的主要方法如下append: 把给定的ByteBufferMessageSet中的Message写入到这个数据文件中。searchFor: 从指定的startingPosition开始搜索找到第一个Message其offset是大于或者等于指定的offset并返回其在文件中的位置Position。它的实现方式是从startingPosition开始读取12个字节分别是当前MessageSet的offset和size。如果当前offset小于指定的offset那么将position向后移动LogOverHeadMessageSize其中LogOverHead为offsetmessagesize为12个字节。read准确名字应该是slice它截取其中一部分返回一个新的FileMessageSet。它不保证截取的位置数据的完整性。sizeInBytes: 表示这个FileMessageSet占有了多少字节的空间。truncateTo: 把这个文件截断这个方法不保证截断位置的Message的完整性。readInto: 从指定的相对位置开始把文件的内容读取到对应的ByteBuffer中。我们来思考一下如果一个partition只有一个数据文件会怎么样新数据是添加在文件末尾调用FileMessageSet的append方法不论文件数据文件有多大这个操作永远都是O(1)的。查找某个offset的Message调用FileMessageSet的searchFor方法是顺序查找的。因此如果数据文件很大的话查找的效率就低。那Kafka是如何解决查找效率的的问题呢有两大法宝1) 分段 2) 索引。数据文件的分段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也不能一次定位到其在数据文件的位置从而需要做一次顺序扫描但是这次顺序扫描的范围就很小了。在Kafka中索引文件的实现类为OffsetIndex它的类图如下主要的方法有append方法添加一对offset和position到index文件中这里的offset将会被转成相对的offset。lookup, 用二分查找的方式去查找小于或等于给定offset的最大的那个offset小结我们以几张图来总结一下Message是如何在Kafka中存储的以及如何查找指定offset的Message的。Message是按照topic来组织每个topic可以分成多个的partition比如有5个partition的名为为page_visits的topic的目录结构为partition是分段的每个段叫LogSegment包括了一个数据文件和一个索引文件下图是某个partition目录下的文件可以看到这个partition有4个LogSegment。借用博主lizhitao博客上的一张图来展示是如何查找Message的。比如要查找绝对offset为7的Message首先是用二分查找确定它是在哪个LogSegment中自然是在第一个Segment中。打开这个Segment的index文件也是用二分查找找到offset小于或者等于指定offset的索引条目中最大的那个offset。自然offset为6的那个索引是我们要找的通过索引文件我们知道offset为6的Message在数据文件中的位置为9807。打开数据文件从位置为9807的那个地方开始顺序扫描直到找到offset为7的那条Message。这套机制是建立在offset是有序的。索引文件被映射到内存中所以查找的速度还是很快的。一句话Kafka的Message存储采用了分区(partition)分段(LogSegment)和稀疏索引这几个手段来达到了高效性。
RELATED

相关推荐

Java中Socket编程1 TCP|UDP通信

Java中Socket编程1 TCP|UDP通信

通信数据源有哪些: 文件、byteArrayOutputStream、socke管道、控制台 1. 基础概念: 1. 地址:Ip地址 2. 端口: 计算机中区分不同进程 同一个协议下,端口不能重复使用,不同协议可以 1024以下端口预留给系统的 比…

📅 2026/9/21 14:18:08
2026超融合替代VMware选型指南:国产平台迁移与评估实践

2026超融合替代VMware选型指南:国产平台迁移与评估实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/18 20:42:07
C#读取通达信股票代码:二进制文件解析与本地数据源构建

C#读取通达信股票代码:二进制文件解析与本地数据源构建

简介:本资源是一套基于C#实现通达信股票代码实时获取的完整Windows Forms桌面应用工程,面向.NET初学者及量化开发入门者,解决在无官方API条件下通过剪贴板机制自动捕获通达信当前选中股票代码的核心问题。压缩包共27个文件,包含7个…

📅 2026/10/7 8:28:43
MORE NEWS

更多资讯

📰

hyperframes揭秘:Rust hyper库HTTP帧处理机制全解析

我第一次看到"hyperframes"这个词,是在翻hyper的源码目录时。当时的第一反应是:这难道又是什么新的前端框架?结果点进去一看,发现是Rust生态里最常被低估的一块底层机制——HTTP协议帧。说起来有点讽刺,绝大…

📰

3D展厅设计不是建模,而是空间叙事重构

1. 项目概述:这不是建模软件操作手册,而是一次展厅空间逻辑的重构“3D展厅展示模型设计与实践”——这八个字背后藏着一个被严重低估的行业真相:90%的所谓“3D展厅”,本质是把产品图贴在立方体墙面上的PPT升级版。真正能让人驻足、…

📰

矩阵分析期末高分攻略:基与过渡矩阵、Jordan标准型等八大题答题模板

简介:这份资源是重庆邮电大学研究生《矩阵分析》期末考卷的PDF,面向备考该课程的高校学生与需要系统梳理矩阵理论的学习者,可用于考前自测、对照复习与查漏补缺。试卷共八大题、满分100分,覆盖线性空间基与过渡矩阵、矩阵1范数与无…

📰

效率工具ponytail:像扎马尾一样轻松收集与整理零散信息

1. 项目从哪来:我自己先"扎起了马尾辫"ponytail 这个名字,第一次听说的人十有八九会以为是个发型教程。实际上它是个纯效率工具,正式点说是一款面向内容收集与快速整理的桌面端插件。我用了一个月,最大的感受是&#xf…

📰

用 PIL 画一套 120 个动态表情包:从 IP 引擎到微信上架的完整工程

t; 目标:为自创 IP「稳喵」产出 5 套收费表情(524120 个 GIF、共 720 帧),全部程序化绘制,零手绘、零外包,两天跑通从像素到微信表情开放平台的完整链路。本文记录整个工程的关键设计与踩坑。一、为什么用 …

📰

UDEC建模参数化:数据表与FISH函数告别手动改命令流

UDEC 建模这件事,我见过太多人把它做成了"文本编辑器里改数字"的体力活。一个三四十行的命令流,倾角改一次、间距改一次、材料号改七八处,改完自己都记不清哪个是原始版本;等到甲方要求换一组工况,翻回去又得…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬