日志长度_Kafka 日志存储详解

点击上方“Java知音”,选择“置顶公众号”

技术文章第一时间送达!

作者:爱宝贝丶

my.oschina.net/zhangxufeng/blog/3114166

本文主要介绍kafka中日志的存储原理,主要内容包括kafka日志存储格式、日志文件的管理方式、日志索引文件的格式和日志压缩等功能。

作为一款消息系统,日志就是将消息持久化到磁盘上的数据,这份数据的存储方式将会极大的影响其吞吐量和扩展性,而kafka日志由于其优秀的设计,为其实现这些特性提供了不可忽略的作用。

总结来说,kafka日志主要具有如下特点:

  • 极高的压缩比例。kafka日志不仅会对其key和value进行压缩,而且还会对每条消息的偏移量、时间戳等等元数据信息进行压缩;

  • batch的方式存储数据。在存储上,kafka日志是以批次的方式进行数据的存储,每个批次的大小默认为4KB,每个批次的元数据中会存储其起始偏移量、时间戳和消息长度等信息;

  • 追加的方式写入数据。由于kafka日志都是写入磁盘的,而磁盘的顺序写入效率是非常高的,kafka写入采用的就是追加的方式写入消息,这样可以避免磁头的随机移动,从而提升写入速率;

  • 使用索引文件提升查询性能。kafka不仅会存储消息日志文件,还会为每个消息日志文件创建一个索引文件,而且索引都是以batch为单位进行存储的,也即只会为batch的起始位移和时间戳建立索引,而不会为每条消息都建立索引。

1. 日志存储格式

最新版本的kafka日志是以批为单位进行日志存储的,所谓的批指的是kafka会将多条日志压缩到同一个batch中,然后以batch为单位进行后续的诸如索引的创建和消息的查询等工作。

对于每个批次而言,其默认大小为4KB,并且保存了整个批次的起始位移和时间戳等元数据信息,而对于每条消息而言,其位移和时间戳等元数据存储的则是相对于整个批次的元数据的增量,通过这种方式,kafka能够减少每条消息中数据占用的磁盘空间。

这里我们首先展示一下每个批次的数据格式:

be51bfab8b22b34129f645e4249b561c.png

图中消息批次的每个元数据都有固定的长度大小,而只有最后面的消息个数的是可变的。如下是batch中主要的属性的含义:

  • 起始位移:占用8字节,其存储了当前batch中第一条消息的位移;

  • 长度:占用了4个字节,其存储了整个batch所占用的磁盘空间的大小,通过该字段,kafka在进行消息遍历的时候,可以快速的跳跃到下一个batch进行数据读取;

  • 分区leader版本号:记录了当前消息所在分区的leader的服务器版本,主要用于进行一些数据版本的校验和转换工作;

  • CRC:对当前整个batch的数据的CRC校验码,主要是用于对数据进行差错校验的;

  • 属性:占用2个字节,这个字段的最低3位记录了当前batch中消息的压缩方式,现在主要有GZIP、LZ4和Snappy三种。第4位记录了时间戳的类型,第5和6位记录了新版本引入的事务类型和控制类型;

  • 最大位移增量:最新的消息的位移相对于第一条消息的唯一增量;

  • 起始时间戳:占用8个字节,记录了batch中第一条消息的时间戳;

  • 最大时间戳:占用8个字节,记录了batch中最新的一条消息的时间戳;

  • PID、producer epoch和起始序列号:这三个参数主要是为了实现事务和幂等性而使用的,其中PID和producer epoch用于确定当前producer是否合法,而起始序列号则主要用于进行消息的幂等校验;

  • 消息个数:占用4个字节,记录当前batch中所有消息的个数;

通过上面的介绍可以看出,每个batch的头部数据中占用的字节数固定为61个字节,可变部分主要是与具体的消息有关,下面我们来看一下batch中每条消息的格式:

2c83a4fe07bd97f2781bb0d08afc36fc.png

这里的消息的头部数据就与batch的大不相同,可以看到,其大部分数据的长度都是可变的。既然是可变的,这里我们需要强调两个问题:

1、对于数字的存储,kafka采用的是Zig-Zag的存储方式,也即负数并不会使用补码的方式进行编码,而是将其转换为对应的正整数,比如-1映射为1、1映射为2、-2映射为3、2映射为4,关系图如下所示:

a14a8c1ea9253ceaf702de329d5f9ba8.png

通过图可以看出,在对数据反编码的时候,我们只需要将对应的整数转换成其原始值即可;

2、在使用Zig-Zag编码方式的时候,每个字节最大为128,而其中一半要存储正数,一半要存储负数,还有一个0,也就是说每个字节能够表示的最大整数为64,此时如果有大于64的数字,kafka就会使用多个字节进行存储。

而这多个字节的表征方式是通过将每个字节的最大位作为保留位来实现的,如果最高位为1,则表示需要与后续字节共同表征目标数字,如果最高位为0,则表示当前位即可表示目标数字。

kafka使用这种编码方式的优点在于,大部分的数据增量都是非常小的数字,因此使用一个字节即可保存,这比直接使用原始类型的数据要节约大概七倍的内存。

对于上面的每条消息的格式,除了消息key和value相关的字段,其还有属性字段和header,属性字段的主要作用是存储当前消息key和value的压缩方式,而header则供给用户进行添加一些动态的属性,从而实现一些定制化的工作。

通过对kafka消息日志的存储格式我们可以看出,其使用batch的方式将一些公共信息进行提取,从而保证其只需要存储一份,虽然看起来每个batch的头部信息比较多,但其平摊到每条消息上之后使用的字节更少了;

在消息层面,kafka使用了数据增量的方式和Zig-Zag编码方式对数据进行的压缩,从而极大地减少其占用的字节数。总体而言,这种存储方式极大的减少了kafka占用的磁盘空间大小。

2. 日志存储方式

在使用kafka时,消息都是推送到某个topic中,然后由producer计算当前消息会发送到哪个partition,在partition中,kafka会为每条消息设置一个偏移量,也就是说,如果要唯一定位一条消息,使用三元组即可。

基于kafka的架构模式,其会将各个分区平均分配到每个broker中,也就是说每个broker会被分配用来提供一个或多个分区的日志存储服务。在broker服务器上,kafka的日志也是按照partition进行存储的,其会在指定的日志存储目录中为每个topic的partition分别创建一个目录,目录中存储的就是这些分区的日志数据,而目录的名称则会以的格式进行创建。如下是kafka日志的存储目录示意图:

31e4df925996516ebe56accce30eaba3.png

这里我们需要注意的是,图中对于分区日志的存储,当前broker只会存储分配给其的分区的日志,比如图中的connect-status就只有分区1和分区4的目录,而没有分区2和分区3的目录,这是因为这些分区被分配在了集群的其他节点上。

在每个分区日志目录中,存在有三种类型的日志文件,即后缀分别为log、index和timeindex的文件。其中log文件就是真正存储消息日志的文件,index文件存储的是消息的位移索引数据,而timeindex文件则存储的是时间索引数据。

如下图所示为一个分区的消息日志数据:

f6157d1a4ec5ef3138df3328ab17c28d.png

从图中可以看出,每种类型的日志文件都是分段的,这里关于分段的规则主要有如下几点需要说明:

  • 在为日志进行分段时,每个文件的文件名都是以该段中第一条消息的位移的偏移量来命名的;

  • kafka会在每个log文件的大小达到1G的时候关闭该文件,而新开一个文件进行数据的写入。可以看到,图中除了最新的log文件外,其余的log文件的大小都是1G;

  • 对于index文件和timeindex文件,在每个log文件进行分段之后,这两个索引文件也会进行分段,这也就是它们的文件名与log文件一致的原因;

  • kafka日志的留存时间默认是7天,也就是说,kafka会删除存储时间超过7天的日志,但是对于某些文件,其部分日志存储时间未达到7天,部分达到了7天,此时还是会保留该文件,直至其所有的消息都超过留存时间;

3. 索引文件

kafka主要有两种类型的索引文件:位移索引文件时间戳索引文件。位移索引文件中存储的是消息的位移与该位移所对应的消息的物理地址;时间戳索引文件中则存储的是消息的时间戳与该消息的位移值。

也就是说,如果需要通过时间戳查询消息记录,那么其首先会通过时间戳索引文件查询该时间戳对应的位移值,然后通过位移值在位移索引文件中查询消息具体的物理地址。关于位移索引文件,这里有两点需要说明:

1、由于kafka消息都是以batch的形式进行存储,因而索引文件中索引元素的最小单元是batch,也就是说,通过位移索引文件能够定位到消息所在的batch,而没法定位到消息在batch中的具体位置,查找消息的时候,还需要进一步对batch进行遍历;

2、位移索引文件中记录的位移值并不是消息真正的位移值,而是该位移相对于该位移索引文件的起始位移的偏移量,通过这种方式能够极大的减小位移索引文件的大小。

如下图所示为一个位移索引文件的格式示意图:

3f50b3dcd5673ab6b8f601d37d63845e.png

如下则是具体的位移索引文件的示例:

8262b7a29ef320327ccefe31cf9645ba.png

关于时间戳索引文件,由于时间戳的变化比位移的变化幅度要大一些,其即使采用了增量的方式存储时间戳索引,但也没法有效地使用Zig-Zag方式对数据进行编码,因而时间戳索引文件是直接存储的消息的时间戳数据,

但是对于时间戳索引文件中存储的位移数据,由于其变化幅度不大,因而其还是使用相对位移的方式进行的存储,并且这种存储方式也可以直接映射到位移索引文件中而无需进行计算。如下图所示为时间戳索引文件的格式图:

edd157db7c322ec8f4a8934027e9b3de.png

如下则是时间戳索引文件的一个存储示例:

0e58665f3b5a7eab9f1b378008e8e48f.png

可以看到,如果需要通过时间戳来定位消息,就需要首先在时间戳索引文件中定位到具体的位移,然后通过位移在位移索引文件中定位到消息的具体物理地址。

4. 日志压缩

所谓的日志压缩功能,其主要是针对这样的场景的,比如对某个用户的邮箱数据进行修改,其总共修改了三次,修改过程如下:

email=john@gmail.com
email=john@yahoo.com.cn
email=john@163.com

在这么进行修改之后,很明显,我们主要需要关心的是最后一次修改,因为其是最终数据记录,但是如果我们按顺序处理上述消息,则需要处理三次消息。

kafka的日志压缩就是为了解决这个问题而存在的,对于使用相同key的消息,其会只保留最新的一条消息的记录,而中间过程的消息都会被kafka cleaner给清理掉。

但是需要注意的是,kafka并不会清理当前处于活跃状态的日志文件中的消息记录。所谓当前处于活跃状态的日志文件,也就是当前正在写入数据的日志文件。如下图所示为一个kafka进行日志压缩的示例图:

4758c9d71109e8d9cb4af29cd68281c0.png

图中K1的数据有V1、V3和V4,经过压缩之后只有V4保留了下来,K2的数据则有V2、V6和V10,压缩之后也只有V10保留了下来;同理可推断其他的Key的数据。

另外需要注意的是,kafka开启日志压缩使用的是log.cleanup.policy,其默认值为delete,也即我们正常使用的策略,如果将其设置为compaction,则开启了日志压缩策略,但是需要注意的是,开启了日志压缩策略并不代表kafka会清理历史数据,只有将log.cleaner.enable设置为true才会定时清理历史数据。

在kafka中,其本身也在使用日志压缩策略,主要体现在kafka消息的偏移量存储。在旧版本中,kafka将每个consumer分组当前消费的偏移量信息保存在zookeeper中,但是由于zookeeper是一款分布式协调工具,其对于读操作具有非常高的性能,但是对于写操作性能比较低,而consumer的位移提交动作是非常频繁的,这势必会导致zookeeper成为kafka消息消费的瓶颈。

因而在最新版本中,kafka将分组消费的位移数据存储在了一个特殊的topic中,即__consumer_offsets,由于每个分组group的位移信息都会提交到该topic,因而kafka默认为其设置了非常多的分区,也即50个分区。

另外,consumer在提交位移时,使用的key为groupId+topic+partition,而值则为当前提交的位移,也就是说,对于每一个分组所消费的topic的partition,其都只会保留最新的位移。如果consumer需要读取位移,那么只需要按照上述格式组装key,然后在该topic中读取最新的消息数据即可。

5. 小结

本文首先对kafka的日志设计的优点进行了介绍,然后着重讲解了日志存储格式、日志目录规划、日志索引文件的格式以及日志压缩的功能。

END

Java面试题专栏

【01期】Spring,SpringMVC,SpringBoot,SpringCloud有什么区别和联系?

【02期】你能说说Spring框架中Bean的生命周期吗?

【03期】如何决定使用 HashMap 还是 TreeMap?

【04期】分库分表之后,id 主键如何处理?

【05期】消息队列中,如何保证消息的顺序性?

【06期】单例模式有几种写法?

【07期】Redis中是如何实现分布式锁的?

【08期】说说Object类下面有几种方法呢?

【09期】说说hashCode() 和 equals() 之间的关系?

【10期】Redis 面试常见问答

b802554fd40086289a6088f1b6fb385d.png

我知道你 “在看e50c6c92e1ab154f2670498315cb8bf7.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/357916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache Spark:更改架构之前必须解决的5个陷阱

迁移到Apache Spark之前需要了解的5件事 似乎每个人都只是在谈论最热门的新技术,而忽略采用它的真正含义。 但这是自然的,对吧? 新功能和承诺胜过其他一切,而艰巨的挑战和决​​定被抛在一边。 这次不行。 软件架构很难&#xf…

双清模式无命令_linux性能监控:IO性能监控命令之iotop命令

内存监控命令之iotop命令1概述:iotop命令 是一个用来监视磁盘I/O使用状况的top类工具。iotop具有与top相似的UI,其中包括PID、用户、I/O、进程等相关信息。Linux下的IO统计工具如iostat,nmon等大多数是只能统计到per设备的读写情况&#xff0…

多生产者_通知:生产者补贴!打卡时间!定了

【生产者补贴!打卡时间定了!9月30日前!】老道说:这几天吉林和黑龙江陆续下发了2020年玉米、大豆生产者补贴实施工作方案!连日来关于生产者补贴方面的消息,也算是逐渐浮出水面!根据黑龙江地区的方…

vaadin_Vaadin附加组件和Maven

vaadin介绍 我喜欢Vaadin的 (其中很多)一件事是它对Vaadin框架的“附加组件”社区-他们称之为Vaadin目录 。 “附加组件”是社区对框架的附加组件,可以是任何东西,例如从新的客户端小部件到数据表的延迟加载容器。 我一定会为Acti…

Beta版本冲刺第二天

队伍CleanCode 031302505 黄晓辉031302223 翁瀚帅031302511 林培兴031302632 张衍坤031302536 苏丽玲一.完成的情况: 继续熟悉了github的使用,开始配置Tomcat服务器环境,增加了号码百事通的号码和游玩福州的一些资料,想要改进α版…

多线程编程反模式_编程反模式

多线程编程反模式您是否曾经进行过代码审查,记录了非常高的WTF / m? 您是否想知道所有这些错误代码的原因是什么? 在大多数情况下,导致原因1的原因是使用设计和编码反模式。 如果您喜欢定义,请参见以下内容&#xff1…

数据挖掘10大算法详细介绍

想初步了解下怎样数据挖掘,看到一篇不错的文章转载过来啦~ 转自:http://blog.jobbole.com/89037/ 在一份调查问卷中,三个独立专家小组投票选出的十大最有影响力的数据挖掘算法,今天我打算用简单的语言来解释一下。 一旦你知道了这些算法是什么…

孙叫兽带你了解腾讯位置服务的认证与接入,多种行业方案参考!

前言:腾讯位置服务为各类应用厂商和开发者提供领先的LBS服务和解决方案;有针对Web应用的JavaScript API, 适合手机端Native APP的各种SDK, WebService接口,适合小程序的插件和各类地图API等。 目录 接入指南 地图组件(H5) 地图javaScri

svn切换分支 如何判断 是否完成_SVN创建分支/合并分支/切换分支

在建立项目版本库时,可首先建好项目文件夹,并在其中建立trunk, branches, tags三个空的子目录。这样在trunk中开始进行开发trunk是主分支,是日常开发进行的地方。branches是分支。一些阶段性的release版本,这些版本是可以继续进行…

圣诞节,程序员应该给女朋友送一个线上圣诞树

前言:圣诞节虽然不是中国的传统节日,但当下很多时髦的年轻人却很喜欢过这个欢乐的节日,并乐于打造参与属于这个节日的仪式感。 除了所知的圣诞老人、圣诞树、互送礼物、吃大餐等传统习俗外,其实程序员能为今天的节日增加一些特别的环节。 圣诞树下载:https://download.csd…

maven 按业务拆分模块_Maven模块拆分方法

一个大项目经常要拆分成多个小模块分开打包,Maven是可以支持模块拆分的。可以包含(父模块即项目包含子模块),也可以并行(父模块和子模块是平级的)。推荐用包含方式,更清晰,更简单一些。首先建个空项目,只要个pom.xml&a…

用户注册,报修

一、需求分析 (1)还没有注册的客户,可以进入注册界面进行注册。 (2)新建一个报修表,名字为repair_info0,列有用户名、报修类型、报修地点、报修内容,报修日期和时间、用户报修次数。…

在HTML中使用css3实现雪人动画效果

背景:圣诞节又到了,拿什么来哄女朋友开心? 项目结构: html: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xht…

圣诞节又到了,作为程序猿的我用代码给女朋友送了一个礼物

圣诞节又到了&#xff0c;拿什么来哄女朋友开心&#xff1f;我们先来做一个简单的雪人动画&#xff1a;项目结构&#xff1a;html:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.d…

【Linux】权限篇(二)

权限目录 1. 前言2. 权限2.1 修改权限2.2 有无权限的对比2.3 另外一个修改权限的方法2.3.1 更改用户角色2.3.2 修改文件权限属性 3. 第一个属性列4. 目录权限5. 默认权限 1. 前言 在之前的一篇博客中分享了关于权限的一些知识&#xff0c;这次紧接上次的进行&#xff0c;有需要…

孙叫兽重磅推荐Chrome插件——CSDN浏览器助手

导读:解决你在浏览器上遇到的各种问题,无论你是学生小白、还是职场老鸟,都可以借助这个插件,打造个性化浏览器,提升工作学习效率。 此插件经过多轮迭代,体积小,内存占用少,便于开发者快速安装和使用。 官方地址:https://plugin.csdn.net/ 目录 安装方法:

【APICloud系列|21】使用APICloud敏捷式开发总结,回顾开发一个完整APP过程。

导读:APICloud是柚子(北京)科技有限公司创建的低代码开发平台,总部位于北京, 通过生产力工具与混合开发技术,为企业与开发者构建高效的IT环境;在APICloud平台已有80万注册用户,平台每日生成安装包超6000个。业务团队延伸至上海、深圳、重庆、青岛等10余个城市。 APICloud是…

数据湖 多维数据集_按汇总分组/多维数据集

数据湖 多维数据集时不时地&#xff0c;您会遇到一个使您达到SQL限制的要求。 我们中的许多人可能会早早放弃并使用Java / [或您的语言]计算内容。 相反&#xff0c;使用SQL可能是如此简单快捷。 如果您使用的是高级数据库&#xff0c;例如DB2 &#xff0c; Oracle &#xff0c…

FlexyPool如何同时支持连接代理和装饰器

代理人 FlexyPool监视连接池使用情况&#xff0c;因此需要拦截连接关闭方法调用。 为了简单起见&#xff0c;第一个版本为此目的依赖动态代理&#xff1a; private static class ConnectionInvocationHandler implements InvocationHandler {public static final String CLOS…

集合视图控制器(CollectionViewController) 、 标签控制器(TabBarController) 、 高级控件介绍...

1 创建集合视图&#xff0c;设置相关属性以满足要求 1.1 问题 集合视图控制器UIConllectionViewController是一个展示大量数据的控制器&#xff0c;系统默认管理着一个集合视图UICollectionView&#xff0c;功能几乎和UITableViewController差不多&#xff0c;能够以多行多列的…