刚才午睡了一会,做了一个梦,Kafka 为什么 ” 这么快 ”,于是乎,便写了这篇探讨的博客文章,网上很多关于 Kafka 测试的文章,测试结果通常都是 Kafka 延迟吊打其他 MQ,那么我们学习一个新东西的时候,首先会想到它会在我们的业务场景中有一个什么样的作用,为什么要用它而不用其他类似的组件,Kafka 学习中,也会有这样的疑问。顺着这个逻辑,我们可能会有两个思路,第一,Kafka 到底是什么?第二,Kafka 的优点?有了这两个概念,我们就可以解决为什么要用它而不用其他组件的问题。
阅读 Kafka 官方文档,寻找这两个问题的答案~
Kafka 到底是什么?
ApacheKafka 是一个分布式流媒体平台。
流媒体平台有三个关键功能:
- 发布和订阅记录流,类似于消息队列或企业消息传递系统。
- 以容错的持久方式存储记录流。
- 记录发生时处理流。
Kafka 通常用于两大类应用:
- 构建可在系统或应用程序之间可靠获取数据的实时流数据管道。
- 构建转换或响应数据流的实时流应用程序。
Kafka 的优点?
- 高吞吐,低延迟
- 持久性、可靠性
- 容错性
- 高并发
- 可扩展性
初步了解了 Kafka 之后,我们现在来一起探讨下 Kafka 低延迟的原理。
Kafka 低延迟的原理
在上面的了解中,知道了 Kafka 有低延迟的优势,它是怎么实现的呢?下面就来一起探讨一下。
生产者 (producer) 写入数据:
Kafka 在收到消息的时候,会把消息持久化存储到硬盘中,为了优化写入速度,Kafka 是这样设计的,顺序写入和运用页缓存技术。
- 首先说一下,为什么顺序写入比随机写入快:先介绍一下它的存储原理。机械硬盘的结构你可以想象成一个唱片机,它有一个旋转的盘片和一个能沿半径方向移动的磁头。处理读取和写入请求时,首先可以根据请求的开始地址算出要处理的数据在磁盘上的位置,之后要进行以下几步工作:1、磁头沿半径方向移动,直至移动到数据所在的柱面(相同半径的磁道组成的环面)2、盘片高速旋转,使磁头到达数据的起始位置 3、磁头沿磁道从磁盘读取或写入数据。当一次读取的数据量很少的时候,1、2 步骤带来的开销是无法忽略的,这使得随机写相对于顺序写会有巨大的性能劣势。因为在顺序写的时候,1、2 步骤只需要执行一次,剩下的全是数据传输所需要的固有开销;而每次随机写的时候,前两个步骤都需要执行,带来了极大的额外开销。
- 其次再说一下页缓存:即便是顺序写入硬盘,硬盘的访问速度还是不可能追上内存。所以 Kafka 的数据并 不是实时的写入硬盘,它充分利用了现代操作系统 分页存储 来利用内存提高 I / O 效率。Memory Mapped Files 也被翻译成 内存映射文件,在 64 位操作系统中一般可以表示 20G 的数据文件,它的工作原理是直接利用操作系统的 Page 来实现文件到物理内存的直接映射。完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候),也就是说,将复杂的 IO 操作交给了操作系统。
消费者 (consumer) 读取数据:
Kafka 在消费数据的时候,为了提高读取速度,运用了零拷贝技术。
- 零拷贝:考虑这样一种常用的情形:你需要将静态内容(类似图片、文件)展示给用户。那么这个情形就意味着你需要先将静态内容从磁盘中拷贝出来放到一个内存 buf 中,然后将这个 buf 通过 socket 传输给用户,进而用户或者静态内容的展示。这看起来再正常不过了,但是实际上这是很低效的流程,我们把上面的这种情形抽象成下面的过程:
1. 首先,调用 read 时,文件 A 拷贝到了 kernel 模式;
2. 之后,CPU 控制将 kernel 模式数据 copy 到 user 模式下;
3. 调用 write 时,先将 user 模式下的内容 copy 到 kernel 模式下的 socket 的 buffer 中;
4. 最后将 kernel 模式下的 socket buffer 的数据 copy 到网卡设备中传送;
幸运的是,你可以用一种叫做 Zero-Copy 的技术来去掉这些无谓的 copy。应用程序用 Zero-Copy 来请求 kernel 直接把 disk 的 data 传输给 socket,而不是通过应用程序传输。Zero-Copy 大大提高了应用程序的性能,并且减少了 kernel 和 user 模式上下文的切换。