磁盘I/O那点事

原文地址: juejin.im/post/5ed992…windows

前言

不知道为何最近喜欢上了看纸质书, 看的关于OS和一点关于硬件方面的东西, 这篇文章算是对最近看的这些作的一个记录吧(这东西明明大学就已经教过了, 偷偷流下了不学无术的泪水).这篇说实话也写了好久, 主要仍是由于天天下班到家基本到了晚上11点(划重点: 终于找到借口了).centos

关于标题

在写完这篇后, 原本打算取一个狂拽酷炫吊炸天的标题, “磁盘I/O都不懂, 连CRUD你都不知道怎么写” , 这样的话点击进来的人应该会多一点, 可是想了想, 如今 贩卖焦虑的营销号已经这么多了, 不缺我一个 , 开发何须为难开发(我本身), 最后决定仍是取个简单点的标题, 说是 "那点事", 可能叫 "磁盘io中的一些事" 会更加恰当一点吧 (文中没有对一些东西进行太多的延伸, 后面可能会加上) , 可是取标题也不能太虚, 就它了.缓存

介绍

磁盘是用于保存大量数据的存储设备, 虽然存储的数据量是 RAM 的不少倍, 可是从磁盘读取信息的延迟为毫秒级, 比DRAM(通常是主存) 的读慢了十万倍, 比从 SRAM(CPU高速缓存存储器) 读慢了100万倍.异步

主要结构

下面是机械硬盘的一个大体的结构图(图画的比较emmm....各位看官将就着看)post

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

每一个磁盘中间都有一根 以固定速率旋转的主轴, 盘片跟随着主轴旋转, 一般是 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

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

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

磁道/扇区:

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

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

题外话: 之前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(page二、三、4)一块儿读取出来, 存放在 page cache当中, 第一次触发的是 同步预读, 也就是上层必须等待这4个page都读取完毕, 而且 page二、三、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有点烫手).

相关文章
相关标签/搜索