Kafka技术知识总结之七——Kafka磁盘存储

接上篇《Kafka技术知识总结之六——Kafka负载均衡策略》

七. 磁盘存储

参考地址:
《Kafka如何实现每秒上百万的高并发写入》
《深入理解 Kafka:核心设计与实践原理》5.5 章节

Kafka 在大数据领域有极为广泛的运用,配置良好的 Kafka 集群甚至可以做到每秒几十万、上百万的超高并发写入。通常磁盘写入是一种非常缓慢的操作,Kafka 的高并发写入主要是依靠页缓存零拷贝两种技术实现的。

7.1 页缓存

操作系统本身有一层缓存,叫做页缓存 (Page Cache),又被称为 OS Cache,即为操作系统自己管理的缓存。页缓存可以将磁盘中的数据缓存到内存中,将对磁盘的访问转换为对内存的访问。
Kafka 大量使用了页缓存,Kafka 在准备将消息写入磁盘中时,可以直接写入页缓存中,接下来操作系统自己决定什么时候将页缓存中的数据真正刷入磁盘中。这样的设计使得 Kafka 将消息写入磁盘的效率大幅提升。
Kafka页缓存

此外 Kafka 写入数据时采用了文件追加的方式写入消息,在日志文件的尾部追加新消息,属于典型的顺序写盘的操作,它依赖于硬盘来存储和缓存消息。通常来说,内存的读写效率要高于磁盘,但磁盘的顺序读写效率也是非常高的,顺序写磁盘的速度甚至高于随机写内存的速率。所以 Kafka 使用了顺序写磁盘的方式做持久化工作。

7.2 零拷贝 (Zero-Copy)

页缓存技术主要用于消息写入 Kafka Broker 端的磁盘,零拷贝技术用于 Kafka Broker 将消息推送给下游消费者。

7.2.1 传统 IO

Kafka Broker 将消息发送给下游的消费者,如果在什么优化都不做的情况下,应该是如下流程:

  1. Kafka Broker 从磁盘中读取消息数据到系统内存;(内核模式)
  2. 系统内存拷贝数据到 Kafka Server 服务的缓存中(内核模式 -> 应用模式)
  3. Kafka Server 服务将缓存中的消息数据复制到操作系统的 Socket 缓存中(应用模式 -> 内核模式)
  4. Socket 缓存将消息数据通过网卡发送出去(内核模式)

上面未优化的过程中,步骤 2 与步骤 3 是没有必要的,这两个步骤中间发生了两次没有必要的上下文切换,而上下文切换是十分消耗性能的。上下文切换状态如下图所示:
传统IO上下文切换

注:传统的拷贝方法为:

  1. 当设备接收到数据,向 CPU 报告中断;
  2. CPU 处理中断;
  3. CPU 将数据从设备寄存器数据读到内存;

传统拷贝方法的步骤 2, 3 是先等待 CPU 中断处理完毕后,再将数据读入内存。而每次的 IO 中断都会带来 CPU 的上下文切换
在现代操作系统中引入了直接内存访问 (DMA, Direct Memory Access) 技术,它允许不同速度的硬件装置沟通,不需要依赖 CPU 的大量中断负载,数据的读写请求由 DMA 控制器接管,减少了 CPU 的负担。

7.2.2 零拷贝技术

参考地址:
《零拷贝简述》
高性能IO背后原理—零拷贝技术概述

Kafka 为了解决这个问题,在读消息时引入了零拷贝技术。零拷贝技术跳过了步骤 2 与步骤 3,跳过了两个上下文切换的步骤,将内核中的数据直接传输给 Socket 缓存,如下图所示。
无描述符零拷贝
上图中的 transferTo() 方法调用过程中的步骤如下:

  1. transferTo() 方法触发 DMA 引擎,将文件内容拷贝到一个读取缓冲区;(内核模式)
  2. 内核将数据拷贝到 Socket 缓冲区;(内核模式)
  3. DMA 引擎将数据从 Socket 缓冲传到网卡设备。(内核模式)

这样就将上下文切换次数减少到两次,即只留下必须的两次切换。但依旧还有优化的内容。因为步骤 2 中的拷贝过程属于重复拷贝,可以将该步骤进行优化。步骤如下:

  1. transferTo() 方法触发 DMA 引擎,将文件内容拷贝到内核缓冲区;(内核模式)
  2. 关于数据的位置和长度的信息的描述符被追加到了 Socket 缓冲;
  3. DMA 引擎将数据从 Socket 缓冲传到网卡设备。(内核模式)

通过使用拷贝描述符的方法取代了拷贝数据,消除了剩下的最后一次 CPU 拷贝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章