Kafka的高吞吐率 —— 为什么顺序 I/O 这么快?

791 阅读5分钟

Kafka的高吞吐率 —— 为什么顺序 I/O 这么快?

学习资料分享,一定要点!!!

实测:顺序的磁盘 I/O 到底有多快?

下面先用 redis 实测一下,看看纯内存读写 100w 条数据耗时几何:

redis纯内存读写速度

可以看到:

操作耗时
100w 数据:内存写960 ms
100w 数据:内存读560 ms
100w 数据:内存读 + 内存写1520 ms

下面用 sed 实测一下,看看基于磁盘 IO 的顺序读写操作速度如何:

磁盘读写速度实测

实测结果:

操作耗时
100w 数据:磁盘读 + 磁盘写55ms
100w 数据:磁盘读42ms
1000w 数据:磁盘读 + 磁盘写514ms
1000w 数据:磁盘读359ms

对比结果:

100w 数据读写操作耗时对比
内存/磁盘 = 560/42 ≈ 13
读 + 写内存/磁盘 = 1520/55 ≈ 28
内存/磁盘 = 960/13 ≈ 74

出乎意料地,磁盘读写速度比内存还要快???

介于我用的是固态硬盘,于是我对比了固态硬盘和机械硬盘的读写速率,如下:

固态硬盘和机械硬盘读写速率对比

最终,对比结果如下:

读写操作读写速率比
顺序读固态:机械 ≈ 18
顺序写固态:机械 ≈ 25
4K 随机读固态:机械 ≈ 175
4K 随机写固态:机械 ≈ 633

通过换算,推断出使用机械硬盘时,磁盘读写速度与内存读写速度的差距如下:

100w 数据读写操作耗时对比
内存/磁盘 = 560/42*18 ≈ 0.74
读 + 写内存/磁盘 = 1520/(42*18+13*25) ≈ 1.4
内存/磁盘 = 960/13*25 ≈ 2.95

通过各项数据对比,总结如下:

  • 磁盘顺序读比内存读慢 35% 左右
  • 磁盘顺序写比内存写更快,大约是内存写的 3 倍
  • 最终,磁盘顺序读写的速度比内存读写的速度还要快 40% 左右

这还仅仅是机械硬盘,如果是固态硬盘,速度更快,以我自己的电脑为例 —— 顺序读写速度是内存读写速度的二十几倍。

 

通过上面数据对比,

发现固态硬盘的顺序读写和随机读写相差几十倍;

机械硬盘的顺序读和随机读相差一百多倍,而顺序写和随机写相差了几百倍。

【思考】

不管是机械硬盘还是固态硬盘,顺序写总是比顺序读慢。

但是为什么固态硬盘随机写比随机读快,机械硬盘随机写比随机读慢?

【解答】

固态硬盘分带缓存和不带缓存的,对于带有动态随机存取存储器(Dynamic Random Access Memory,DRAM, 一种半导体存储器)的固态硬盘:

随机读操作是真的要去操作磁盘,但随机写却不一定立刻落盘,实际上直接操作的对象是 DRAM。所以固态硬盘的随机写看上去比随机读还要快。

【为什么读就理所当然要比写快呢?】

抛开缓存不谈,磁盘读操作利用索引可以让读取速度非常快;而写操作需要根据寻道策略去寻找可用扇区,还要确认没有数据后才能写入,还要维护标志位,所以耗时比读操作更长。

而且写操作需要给电子提供更大的能量,功耗更高。

 

顺序的磁盘 I/O 为什么快?

Kafka 能够以 O(1) 的时间复杂度(不使用随机读写,使用顺序读写)提供消息持久化能力,即使对 TB 级以上的数据也能保持常数时间的访问性能。

顺序读写为何能那么快呢?

下面是磁盘的内部结构图

磁盘内部结构图

磁盘的物理地址由【柱面号 + 盘面号 + 扇区号】来定义,磁盘核心部位详解:

磁盘的结构

根据地址读写一个“磁盘块”的流程如下:

  1. 根据 柱面号 移动磁臂,让磁头指向指定柱面;
  2. 激活 盘面号 对应的磁头;
  3. 磁盘旋转,扇区号 所代表的扇区从磁头划过就完成了对指定扇区的读/写。

下面我们以 7200rpm 的硬盘为例,先来计算1 次随机读写耗时

  • 首先是磁臂根据柱面号移动到指定柱面的时间,称为寻道时间,一般为 7.5 ~ 14 ms

  • 然后是磁盘旋转,找到指定扇区:

    • 每分钟 7200 转,则每秒转数:7200 / 60 = 120
    • 转 1 圈花费时间:120 / 1000ms = 8.33 ms
    • 平均只需转半圈即可找到指定扇区,所以旋转延迟时间4.165 ms
  • 最后是磁头进行读写操作的传输时间,这取决于要读写的字节数。

那么,N 次随机读写的耗时就是:

N 次寻道时间 + N 次旋转延迟时间 + N 次传输时间

N 次顺序读写的耗时为:

1 次寻道时间 + 1 次旋转延迟时间 + N 次传输时间

 

也就是说,寻道时间和旋转延迟时间被均摊到 N 次顺序 IO 中,在大量的 IO 次数面前,几乎可以忽略不记。

这就是为什么顺序磁盘 I/O 比随机磁盘 I/O 要快得多。

 

假设:

  • 每次读取 1 字节的数据
  • 扇区大小 512 字节
  • 扇区数 63
  • 转一圈耗时 8.33 ms

可以算出读取 1 字节的数据 100w 次,需要时间:

# 1 次寻道时间 + 1 次旋转延迟时间 + 1字节数据传输时间 * 1000000
11 + 4.165 + 8.33 * 1 / (512*63) * 1000000 = 15.165 + 258.2465273.4 ms