转载自 huxihx,原文链接 【原创】Kafka 0.11消息设计

目录

一、Kafka消息层次设计

1. v1格式

2. v2格式

二、v1消息格式

三、v2消息格式

四、测试对比

Kafka 0.11版本增加了很多新功能,包括支持事务、精确一次处理语义和幂等producer等,而实现这些新功能的前提就是要提供支持这些功能的新版本消息格式,同时也要维护与老版本的兼容性。本文将详细探讨Kafka 0.11新版本消息格式的设计,其中会着重比较新旧两版本消息格式在设计上的异同。毕竟只有深入理解了Kafka的消息设计,我们才能更好地学习Kafka所提供的各种功能。    

一、Kafka消息层次设计

不管是0.11版本还是之前的版本,Kafka的消息层次都是分为两层:消息集合(message set)以及消息(message)。一个消息集合中包含若干多条日志项,而每个日志项封装了消息以及其他一些元数据。Kafka底层的消息日志则由一系列消息集合日志项组成的。Kafka不会在消息这个层面上直接操作,它总是在消息集合这个层面上进行写入操作。

新旧两个版本对这两个层次的设计都有很大区别,我们下面分开来说。不过在深入到具体版本之前,我们先要明确一些基本术语。

首先,我会遵循Kafka社区的规范,称老版本消息格式为v1,新版本格式为v2。另外这里所指的老版本是指包含了时间戳(timestamp)字段的消息格式,更早之前的消息格式不在本文讨论的范围。其次,消息集合和消息在新旧版本对应的类名也有些许区别:

1. v1格式

在0.11版本之前,消息集合对应的类是org.apache.kafka.common.record.Records,消息是o.a.k.common.record.Record。消息集合中的每一项被称为日志项(log entry),你可以理解每个日志项都是一个batch。

2. v2格式

0.11版本中消息集合对应的类是o.a.k.common.record.RecordBatch,消息依然是o.a.k.common.record.Record。特别注意这里的RecordBatch,如果你在之前的Kafka版本中搜寻RecordBatch类,你会发现在老版本中它指代的是Java producer端的消息batch——java producer将待发送消息收集起来,然后根据topic分区执行分组操作,其分组结果就保存在多个RecordBatch中。但是在新版本中,RecordBatch指的是普通的消息集合,producer端的分组batch由类o.a.k.clients.producer.internals.ProducerBatch来负责。各位千万不要混淆!

okay,了解了基本的术语,我们分别讨论下老版本、新版本的消息格式。

二、v1消息格式

在0.11版本之前,Kafka的消息格式如下图所示:

图中各个字段的含义很清晰,这里不再赘述。从上图中我们可以计算出来一条普通的Kafka消息的头部开销——这里姑且称为头部,header,但不要和新版本的header混淆!下面会讨论新版本的header。此版本的消息头部开销等于4 + 1 + 1 + 8 + 4 + 4 = 22字节,也就是说一条Kafka消息长度再小,也不可以小于22字节,否则会被Kafka视为corrupted。另外根据这张图展示出来的格式,我们能够很容易地计算每条Kafka消息的总长度。注意,这里我们讨论的未压缩消息。已压缩消息的计算会复杂一些,故本文暂且不讨论。

下面我们来做一些计算。假设有一条Kafka消息,key是“key”,value是“hello”,那么key的长度就是3,value的长度就是5,因此这条Kafka消息需要占用22 + 3 + 5 = 30字节;倘若另一条Kafka消息未指定key,而value依然是“hello”,那么Kafka会往key长度字段中写入-1表明key是空,因而不再需要保存key信息,故总的消息长度= 22 + 5 = 27字节。当然value字段也可能是null——Kafka的log cleaner会定期地写入这种被称为tombstone消息,不过计算方法与key为空时是相同的。总之单条Kafka消息长度的计算是很简单的,下面我们来说说消息集合日志项的计算。

老版本消息集合中的每一项的格式如下图所示:

aaarticlea/png;base64,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" alt="" />

如图所示,每个消息集合中的日志项由日志项头部+一条“浅层”消息构成。

  • 浅层(shallow)消息:如果是未压缩消息,shallow消息就是消息本身;如果是压缩消息,Kafka会将多条消息压缩再一起封装进这条浅层消息的value字段。这条浅层消息也被称为wrapper消息,里面包含的消息被称为内部消息,即inner message。由此可见,老版本的message batch中通常都只包含一条消息,即使是对于已压缩消息而言,它也只是包含一条shallow消息。
  • 日志项头部(log entry header):8字节的offset字段 + 4个字节的size字段,共计12个字节。其中offset保存的是这条消息的位移。对于未压缩消息,它就是消息的位移;如果是压缩消息,它表示wrapper消息中最后一条inner消息的位移。由此可见,给定一个老版本的消息集合倘若要寻找该消息集合的起始位移(base offset或starting offset)是一件很困难的事情,因为这通常都需要深度遍历整个inner消息,这也就是意味着broker端需要执行解压缩的操作,因此代价非常高。

下面我们来看下如何计算消息集合大小,还是拿之前的两条Kafka消息为例。第一条消息被封装进一个消息集合,那么该消息集合总的长度 = 12 + 30 = 42字节,而包含第二条未指定key消息的消息集合总长度 = 12 + 27 = 39字节。我们做个试验来验证下:

1. 创建一个测试topic,1个分区,replication-factor = 1,然后使用console-producer脚本发送一条消息,key=“key”,value=“hello”,然后验证下底层文件日志大小是42字节。

bogon:kafka_0.10.2. huxi$ bin/kafka-topics.sh --zookeeper localhost: --create --partitions  --replication-factor  --topic test
Created topic "test".
bogon:kafka_0.10.2. huxi$ bin/kafka-console-producer.sh --broker-list localhost: --topic test --property parse.key=true --property key.separator=:
key:hello

输出结果:

bogon:test- huxi$ pwd
/Users/huxi/SourceCode/testenv/datalogs/kafka_1/test-
bogon:test- huxi$ ll *.log
-rw-r--r-- huxi staff Jul : .log

可见,我们的计算是正确的。

2. 再使用console-producer脚本发送另一条消息,不指定key,value依然是“hello”,然后验证下底层文件日志大小是42 + 39 = 81字节。

bogon:test- huxi$ ll *.log
-rw-r--r-- huxi staff Jul : .log

结果再次证明我们的计算方法是正确的。不过,老版本的消息集合在设计上有一些弊端,包括:

  • 对空间的利用率不高,比如不论key和value的长度是多少,老版本消息都是用固定的4个字节来保存长度信息,比如value是100字节还是1000字节,v1消息都需要花费4个字节来保存整个值,但其实保存100这个值只需要7个比特就够了,也就是说只用1个字节就可以,另外3个字节都是浪费的。如果你的系统中这种情况很常见的话,那么对于磁盘/内存空间的浪费是十分可观的。
  • 老版本设计中的offset是消息集合的最后一条消息的offset,如果用户想要获取第一条消息的位移,必须要把所有消息解压全部装入内存然后反向遍历才能获取到。显然这个代价是很大的
  • CRC的计算有些鸡肋。老版本设计中每条消息都需要执行CRC校验。但有些情况下我们不能想认为producer端发送的消息的CRC到consumer端消息时是不变的。比如如果用户指定的时间戳类型是LOG_APPEND_TIME,那么在broker端会对消息时间戳字段进行更新,那么重新计算之后的CRC值就会发生变化;再比如broker端进行消息格式转换也会带来CRC的变化。鉴于这些情况,再对每条消息都执行CRC校验就有点没必要了,不仅浪费空间还耽误CPU时间
  • 每次需要单条消息的总长度信息时都需要计算而得出,没有使用一个字段来保存下来,解序列化效率不高。

鉴于以上这些弊端以及对0.11版本新功能支持的需要, Kafka社区重新设计了v2版本的消息来解决以上的问题。

三、v2消息格式

v2版本依然分消息与消息集合两个维度,只不过消息集合这个提法被消息batch所取代。v2版本的术语叫RecordBatch。我们先来看v2消息的格式,如下图所示:

这里的"可变长度"表示Kafka会根据具体的值来确定到底需要几个字节来保存。为了序列化时降低所需的字节数,0.11版本借鉴了Google PB的Zig-zag编码方式,使得绝对值较小的整数占用比较少的字节。这是符合Kafka消息使用场景的,毕竟在实际使用过程中,key或value很大的可能性并不高。比如key如果是一个有业务含义的字符串(这是很常见的使用方法),那么这个字符串的长度通常都不会太长,这样大部分情况下只需要1~2个字节就可以保存了。这比v1版本中固定使用4个字节来保存要节省得多。如果要深入了解pb的编码方式请参考:https://developers.google.com/protocol-buffers/docs/encoding

总之v2版本的消息格式比起v1有很大的变化。除了可变长度这一点,v2版本的属性字段被弃用了,CRC被移除了,另外增加了消息总长度、时间戳增量(timestamp delta)、位移增量(offset delta)和headers信息。我们分别说下:

  • 消息总长度:直接计算出消息的总长度并保存在第一个字段中,而不需要像v1版本时每次需要重新计算。这样做的好处在于提升解序列化的效率——拿到总长度后,Kafka可以直接new出一个等长度的ByteBuffer,然后装填各个字段。同时有了这个总长度,在遍历消息时可以实现快速地跳跃,省去了很多copy的工作。
  • 时间戳增量:消息时间戳与所属record batch起始时间戳的差值,保存差值可以进一步节省消息字节数
  • 位移增量:消息位移与所属record batch起始位移的差值,保存差值可以进一步节省消息字节数
  • headers:这和本文之前提到的所有header都无关。这是0.11版本引入的新字段。它是一个数组,里面的Header只有两个字段:key和value,分别是String和byte[]类型。
  • v2版本不在对每条消息执行CRC校验,而是针对整个batch
  • v2版本不在使用属性字节,原先保存在属性字段中的诸如压缩类型、时间戳类型等信息都统一保存在外层的batch中

下面我们依然拿上面的Kafka消息举例计算下0.11版本的消息长度是多少。假设这条Kafka消息的key是“key”,value是“hello”,同时假设这是batch中的第一条消息,因此时间戳增量和位移增量都是0,另外我们还假设没有指定任何header,因此header数组个数是0。结合上图我们可以计算这条消息的长度 = 总长度值占用的字节数 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 1 =  总长度值占用的字节数 + 14,由于14小于64,因此总长度值只需1个字节,故消息总长度是15字节。同时消息的第一个字节保存的值就是15。这里提一句为什么是64? 先前提到的Zigzag编码会将有符号32位整数编码成一个无符号整数,大致的思想是:

   --->
-  --->
  --->
-   --->
  --->
...

这样做,我们不再需要为-1去保存32位的补码,只需要1个字节就能保存-1,但是zigzag会将每个字节的第一个比特作为特殊之用,故每个字节只能有7位来做实际的编码任务,也就是表示从0~127。上面的编码表中我们可以发现正数都会被编码成其2倍的数字,因此如果一旦上面例子中的长度超过了128/2=64,长度信息就需要用2个字节来保存。这就是上面64这个数字出现的原因。(希望我解释清楚了。。。。) 我们再举个例子,假设某条Kafka消息未指定key,value是“hello”,该消息在整个batch中的第100条且时间戳增量也是100,那么该消息总的字节数是=总长度值占用的字节数 + 1 + 2 + 2 + 1 + 1 + 5 + 1 = 总长度值占用的字节数 + 13 = 14字节。

谈完了消息格式,我们终于可以说说record batch了。v2的batch格式非常复杂,不废话了, 直接上图:

显然这比v1版本的batch要复杂得多,简单解释一下它和v1的主要区别:

  • CRC被移动batch这一层,而非消息这一层
  • 属性字段被扩充为2个字节,而不是之前的一个字节,其中第一个字节的低3位比特保存压缩类型,第4个比特保存时间戳类型,第5个比特保存消息的事务类型(事务型消息和非事务型消息),第6个比特指定batch是否是control batch(control batch以及control message用于支持事务)
  • PID、producer epoch、序列号等信息都是为了实现幂等producer之用,故本文不做详细展开(其实我也不会

    Kafka设计解析(十六)Kafka 0.11消息设计的更多相关文章

    1. 【原创】Kafka 0.11消息设计

      Kafka 0.11版本增加了很多新功能,包括支持事务.精确一次处理语义和幂等producer等,而实现这些新功能的前提就是要提供支持这些功能的新版本消息格式,同时也要维护与老版本的兼容性.本文将详细 ...

    2. 揭秘Kafka高性能架构之道 - Kafka设计解析(六)

      原创文章,同步首发自作者个人博客.转载请务必在文章开头处以超链接形式注明出处http://www.jasongj.com/kafka/high_throughput/ 摘要 上一篇文章<Kafk ...

    3. Kafka设计解析(六)Kafka高性能架构之道

      转载自 技术世界,原文链接 Kafka设计解析(六)- Kafka高性能架构之道 本文从宏观架构层面和微观实现层面分析了Kafka如何实现高性能.包含Kafka如何利用Partition实现并行处理和 ...

    4. Kafka设计解析(六)- Kafka高性能架构之道

      本文从宏观架构层面和微观实现层面分析了Kafka如何实现高性能.包含Kafka如何利用Partition实现并行处理和提供水平扩展能力,如何通过ISR实现可用性和数据一致性的动态平衡,如何使用NIO和 ...

    5. Cocos2dx 3.0 过渡篇(二十六)C++11多线程std::thread的简单使用(上)

      昨天练车时有一MM与我交替着练,聊了几句话就多了起来,我对她说:"看到前面那俩教练没?老色鬼两枚!整天调戏女学员."她说:"还好啦,这毕竟是他们的乐趣所在,你不认为教练每 ...

    6. ROS探索总结(十六)——HRMRP机器人的设计

      1. HRMRP简介         HRMRP(Hybrid Real-time Mobile Robot Platform,混合实时移动机器人平台)机器人是我在校期间和实验室的其他小伙伴一起从零开 ...

    7. MySql(十六):MySql架构设计——MySQL Cluster

      前言: MySQL Cluster 是一个基于 NDB Cluster 存储引擎的完整的分布式数据库系统.不仅仅具有高可用性,而且可以自动切分数据,冗余数据等高级功能.和 Oracle Real Cl ...

    8. Hadoop HBase概念学习系列之优秀行键设计(十六)

      我们通过行键访问HBase.尽管使用扫描过滤器可以一次性指明大量的键,但是HBase仅仅能够根据行键识别出一行. 优秀的行键设计可以保证良好的HBase性能. 1.行键存在于HBase中的每一个单元格 ...

    9. Unity 游戏框架搭建 (十六) v0.0.1 架构调整

      背景: 前段时间用Xamarin.OSX开发一些工具,遇到了两个问题. QFramework的大部分的类耦合了Unity的API,这样导致不能在其他CLR平台使用QFramework. QFramew ...

    随机推荐

    1. Springmvc中的HandlerAdaptor执行流程

      今天讲解一下在Springmvc中的HandlerAdaptor执行流程,明白这个过程,你就能画出下面的图: 接下来我们就来看看具体的实现过程吧. 1.0在DispatcherServlet中找到ge ...

    2. 在AE二次开发中出“正试图在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。”异常解决方案

      今天的一个项目总用到了AE的开发组件,也就是ESRI公司提供的一系列的开发包(组件)都是以dll(动态链接库的形式)然后今天在调试的时候却出现了“正试图在 OS 加载程序锁内执行托管代码.不要尝试在 ...

    3. Codeforces 981H:K Paths

      传送门 考虑枚举一条路径 \(u,v\),求出所有边经过它的答案 只需要求出 \(u\) 的子树内选出 \(k\) 个可以重复的点,使得它们到 \(u\) 的路径不相交 不难发现,就是从 \(u\) ...

    4. AGC006C Rabbit Exercise

      传送门 设 \(f_{i,j}\) 表示兔子 \(i\) 在当前 \(j\) 轮的期望位置 对于一次操作 \(f_{i,j+1}=\frac{1}{2}(2f_{i-1,j}-f_{i,j})+\fr ...

    5. setInterval和setTimeout的区别以及setInterval越来越快问题的解决方法

      setInterval()和setTimeout()方法都是js原生的定时方法,当然它们两个的作用也是不同的,并且最近在做上下滚动公告栏的时候,发现了setInterval()非常令人抓狂的问题,那就 ...

    6. 原 java调整数据顺序是奇数位于偶数的前面(思路与实现)

      题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 思路一: 首先这 ...

    7. 地图经纬度坐标与屏幕坐标的转换(android版)

      我们在开发GIS系统的时候,首先要解决的就是地图的可视化问题,这个问题的关键就在于如何把地图的坐标转换成屏幕坐标,然后才到渲染着色.标注等.以下以wgs84经纬度坐标为基准,介绍一下地图经纬度坐标与屏 ...

    8. JSON学习笔记-5

      JSON.parse() 1.从服务器接受数据进行解析(一般是字符串) 2.解析前要确保你的数据是标准的 JSON 格式,否则会解析出错.可以使用线工具检测:https://c.runoob.com/ ...

    9. Android埋点技术分析

      1.现有的几种埋点技术的实现原理和优劣分析 (1)代码埋点:将收集数据的代码直接写在需要的地方,当用户点击某个控件或者打开某个页面时调用到该部分代码完成数据的收集. 优势:准确性高,收集数据和发送数据 ...

    10. 全局css,js缓存及更新版本策略

      在当今web世界里,CDN对于加速页面加载速度,提高用户体验起了非常重要的作用.但是问题也带来了:作为开发人员,可能需要不定时的更新部分静态文件,比如对网页的重新设计会涉及到css文件的更新,这时怎么 ...