磁盘I/O那点事

作者: LemonNan

原文地址: https://juejin.im/post/5ed992f7f265da76bb013e72

介绍

磁盘是用于保存大量数据的存储设备, 虽然存储的数据量是 RAM 的很多倍, 但是从磁盘读取信息的延迟为毫秒级, 比DRAM(一般是主存) 的读慢了十万倍, 比从 SRAM(CPU高速缓存存储器) 读慢了100万倍. 本文将对磁盘做一个简单的介绍.

主要结构

下面是机械硬盘的一个大致的结构图
在这里插入图片描述

主轴、盘片、传动臂、读写头、磁道/扇区

每个磁盘中间都有一根 以固定速率旋转的主轴, 盘片跟随着主轴旋转, 通常是 5400 ~ 15000RPM(我的希捷1T就是7200RPM), 一个磁盘通常包含很多个这样的盘片.

每个盘片中都由一组称为磁道的同心圆组成, 每个磁道被划分为一组扇区. 每个扇区包含相同的数据位(通常是512字节,下面是一些输出信息)

// 下面是在某台 centos7.2上面的数据
[root@xxxxx ~]# fdisk -l

磁盘 /dev/vda:42.9 GB, 42949672960 字节,83886080 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理)512 字节 / 512 字节
I/O 大小(最小/最佳)512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x000d2717

磁盘操作

磁盘操作的时候, 需要几个部分的东西, 传动臂、读写头、磁道/扇区.

传动臂: 传动臂的作用是将读写头定位到盘片上的磁道上, 这个叫 寻道, 后面还会出现 .

读写头: 位于传动臂末端, 用于读写数据, 磁盘上的 每个盘片都有一个独立的读写头.

磁道/扇区:

扇区: 扇区是一条磁道上的一块, 磁盘以扇区为最小单位读写数据(扇区是最小的物理存储单元).

磁道: 盘片上的每个同心圆都是一条磁道, 一条磁道由多个扇区和扇区之间的间隙组成(最外圈的磁道长度最长, 扇区最多, 所存储的数据也是最多的).

题外话: 以前google在最开始做优化搜索的一个步骤是将热点数据放在磁盘外圈, 因为盘片是一个同心圆, 角速度是一样的, 相同时间内, 最外圈的磁道走过的路径是最长的, 也就是相同时间, 最外圈读取到的数据是最多的.

磁盘具体操作流程

  • (寻道时间) 首先接收到要读取的数据的物理位置, 传动臂将读写头定位到数据对应的磁道, 一般这个寻道的时间单位为 ms.

  • (旋转时间) 定位到对应磁道上后, 接着等待读写头定位到该磁道上数据对应的扇区的第一个字节.

  • (传输时间) 从磁盘读出或者写入数据, 通常这个时间是最低的.

所以访问磁盘的总时间是: 寻道时间 + 旋转时间 + 传输时间.

在机械硬盘的磁盘I/O中, 通常磁盘I/O的时间影响: 寻道 > 旋转 >> 传输.

时间

寻道时间

目前一般的硬盘的寻道时间为 7.5~14ms. 平均寻道时间为 Tavg seek = 9ms;

平均旋转时间

盘片旋转一圈所需时间的一半 , 拿我的 7200RPM 机械硬盘 举例, 一分钟旋转 7200 圈, 7200/60 = 120 圈/秒, 一圈所需的时间就是 1/120(s), 所以最后得出的 平均旋转时间就是 1/120/2 = 1/240(s), 大概 4ms 出一点.

数据传输时间

数据传输时间相对于前两个时间来说, 通常可以忽略不计, 但还是有的(偷懒).

随机I/O和顺序I/O

随机I/O

随机I/O的流程就是像上面说的磁盘操作流程那样, 每次读写数据都需要经过完整的步骤: 寻道、旋转、传输 , 也就是每一次读写数据都需要将读写头定位到对应的磁上, 读写比较频繁的时候, 就会出现一会定位内圈, 一会定位外圈, 简称反复横跳(好像哪里听过的样子), 磁盘的操作时间大部分都花在了第一步的寻道还有第二部的旋转上(因为只有寻道+旋转才能确定最终数据的位置).

顺序I/O

既然是分开了, 那顺序I/O自然就是不需要或者说几乎没有寻道时间, 因为顺序I/O的话, 基本上是在同一个磁道进行操作或者邻近的磁道进行操作, 这时候的寻道次数非常少, 相比随机I/O, 效率自然是更高的.

至于后面的传输时间, 两种类型的I/O都是一样的.

随机I/O如何变成顺序I/O

Q: 如何将随机I/O转化成顺序I/O?

A: 要知道怎么实现, 先要知道他们的区别: 随机I/O和顺序I/O的区别就是寻道和旋转的次数, N次随机I/O需要寻道N次、旋转N次, 而顺序 I/O 最好的情况是寻道1次、旋转1次, 即使不是1次, 读写数据也是在第一次寻道后的邻近的磁道读写, 所以寻道时间和旋转时间肯定是 远远低于N次随机I/O的时间. 所以如果是要变成顺序I/O的话, 数据在空间上必须是连续的, 才能实现顺序读写.

so 数据最好是作为一个整体, 统一读取/写入, 整块的数据就是连续的, 就可以实现顺序I/O.

性能

衡量磁盘的重要主要指标是IOPS和吞吐量

IOPS&吞吐量

IOPS(Input/Output Per Second)即美妙读写次数, 就像QPS,

磁盘的IOPS = 1000(ms)/(寻道时间+旋转时间+传输时间).

按照上面的数据 (寻道时间+旋转时间+传输时间(这里忽略不计)) = 9+4 = 13ms, 1000/13 ≈ 76左右.

吞吐量(Throughput),指单位时间内可以成功传输的数据数量.

测试

机械硬盘

(为了白piao一下读写性能的测试结果, 上了某东打开了家里电脑的希捷7200RPM 1T的商品页面, 问客服要了读写性能的链接, 结果客服居然说商家没给他们具体的读写性能参数, 可能是我想多了?打扰了~)

于是开启了自己的windows, 下了个性能测试软件进行I/O性能测试, 下面是测试的结果图.

机械硬盘性能测试

可以看到Seq的比没有Seq的高出了非常多. 没错, Seq就是顺序I/O, 没有Seq的就是随机I/O, 性能差距一下体现出来了. 顺序I/O的性能达到了 150MB/s 左右, 而随机I/O位于 0.5 ~ 1.5MB/s之间,

测试多几次结果可能会不同, 但不会相差太大.

固态硬盘

先发一下还是我的windows电脑上面, 用在C盘上的固态

固态硬盘性能测试

从数据可以看到, 固态硬盘的数据几乎都是遥遥领先, 因为固态硬盘在物理结构上和机械硬盘的差别导致的, 固态由半导体构成, 没有移动的部件, 所以访问的效率比机械硬盘高.

OS 中的优化处理(莫非说的就是Linux)

先说一下在计算机中的一个原理, 局部性原理.

局部性原理:当某个数据被使用到的时候, 跟它邻近的数据也很可能会在后面被使用到.

在Linux中, 正是基于这个原理, 对磁盘I/O做了一些的优化.

预读

当第一次读取磁盘数据的时候, 比如只读取 page1(4k), Linux 会同步的将后面 几(3)个 page(page2、3、4)一起读取出来, 存放在 page cache当中, 第一次触发的是 同步预读, 也就是上层必须等待这4个page都读取完毕, 并且 page2、3、4 被做了预读的标记. 当要读page2的数据的时候, 因为之前已经读取出来了, 在 page cache中可以找到, 所以直接在page cache中读取即可, 并且因为做了预读标记, 表明这个预读是有效的, 接下来会触发第二次的预读, 但这次是 异步预读, 上层需要的数据从page cache cp过去即可, 底层的这次异步预读对上层程序是透明的, 这次会读取 page5 ~page8 放入到 page cache 当中, 并且也做上标记, 再后面会继续沿用第二次异步预读的流程.

这让我想起了 MySQL 中的一个page大小默认为 16K, 会不会纯属是巧合呢??

这是预读的情形, 还有一种就是后写的情况.

后写

在OS每次接收到I/O请求的时候, 不会每次都去进行磁盘写入, 如果每次都写入的话, 效率就像上面测试的随机I/O那样, 为了优化这种情况, OS在进行写入的时候, 会进行写入合并, 将相邻的写请求进行合并以至于至少可以进行 局部的顺序I/O , 这种处理提高了很多磁盘写入的效率. 所以在经过OS的这个优化后, 最终的IOPS会超过计算出来的IOPS.

Kafka 中的消息都是通过日志追加的方式 , 在查找的时候先通过二分查找对应 partition 下面的 Segment, 实际上kafka是维护了一个 Segment 的跳表结构, 找到对应的 Segment, Segment上的文件数据都是顺序读写, 实际上 partition 也是顺序读写, 这也是为什么Kafka的吞吐能达到十万级的原因之一.

批量操作大部分情况下都是有好处的, 要不是有OS的优化, 怕是真的连日常CRUD都不会写.

最后

这次算是对磁盘I/O相关的一次记录吧(不说了, 最近的bug有点烫手).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬楠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值