磁盘这玩意儿,即使不作为一个开发人员我们也会经常跟它打交道。比如你家里的台式机,或者拿来办公的电脑,再比如你装个操作系统,会涉及到对磁盘进行分区。
而作为开发人员,自然更加需要关注磁盘。
平时你开发的代码会暂存在磁盘上;开发中用的最多的数据库 MySQL,其数据是持久化到磁盘中的;Redis 的持久化数据是落到磁盘的;Zookeeper 内存中的数据、事务日志、快照会持久化到磁盘;像 RocketMQ 这种消息队列也会将收到的 Message 持久化到磁盘,Kafka 当然也不例外;
可以说,磁盘和我们的开发息息相关。但可能在平时的开发中,很多人会忽略掉磁盘的存在,因为虽然息息相关,但很遗憾,不是直接相关。因为上面提到的所有的和磁盘相关的内容,都已经由工具帮我们做了,甚至包括你的代码。
这种感觉就好像,鱼(可能)不怎么注意水,我们平时不太会注意氧气。
我们可能听过,磁盘 IO 慢,为什么?我们可能听过,磁盘顺序 IO 会快些,为什么?我们可能听过磁盘的顺序 IO 甚至比内存随机 IO 要快,为什么?
可能这些问题,我们都不一定能做个清晰的解释,这也是为什么我想聊聊磁盘。
磁盘分类
首先,按照原理来分,磁盘可以分为三类:
- 机械硬盘(HDD)
- 固态硬盘(SSD)
- 混合硬盘(SSHD)
本篇文章的重点会放在 HDD 上。
场景切入
首先还是通过一个很简单的场景来切入,如下:
你在你的电脑上创建了个文件,然后写了点东西进去。然后你 N 天后打开电脑,看到这个文件还在(废话)。这实际上就是数据被持久化进了磁盘,下次需要文件时再从磁盘中取出来。
这个存、取的过程其实对我们完全无感知的,我们就知道装机的时候安了一块硬盘,其他的啥也不知道。
磁盘结构
那磁盘里究竟长啥样呢?它是怎么样把文件存储起来的?以什么样的方式存储的?带着这样的问题来看一个图:
图片来自 wikipedia
结合上面的结构图可以看出来,现代主流的磁盘设计就是在一个 Spindle(主轴)上,有一些 platter(盘片),然后盘片会绕着主轴旋转,然后读数据、写数据则由读写磁头来实现,读写磁头会安装在磁头臂上,磁头臂可以转动,覆盖到盘片的所有的半径,再搭配主轴的旋转,从而使磁头可以获取到盘片上任何一个扇区的数据。
那你可能会好奇了,这个盘片到底要怎么做、怎么设计才能把上文提到的文件给存储下来呢?
要知道,现在的磁盘盘片大多都是由非磁性材料,通常是铝合金、玻璃或者陶瓷制成的,你的印象中,他们能够拿来存储文件吗(再次手动狗头)
既然提到了非磁性,那么答案肯定就跟磁性有点关系...
盘片构造
没错,盘片的两个面会被涂上一层薄薄的磁性材料,有多薄呢?大概是 10-20 纳米,然后外面给包了层碳来作为保护,这层薄薄的磁性材料就是存储数据的关键
磁性材料
一个磁盘一般都会有多个盘片,并且刚刚提到的磁性材料盘片的两个面都有。换句话说,盘片的两个面都能用于存储、读取数据。
现在我们知道了,数据其实是存在磁性材料上的,那这里再思考一个问题:「磁盘怎么知道,数据该存在哪块磁性材料上?读取的时候又该从哪块材料上读?读多少?」
这个道理其实跟我们的地图是类似的,举个例子,中国这么大,我们要如何清晰、准确的描述某一个地方呢?这个答案其实大家都知道,那就是分层分级。
举个例子,网购让你填的收货地址就是这样,比如「四川省-成都市-xx区-xx街道-x栋x号-xxxx室」,这样的分层逻辑能够很直观的表示一个特定、具体的位置,而不用说大概那一块,先往中国西南走、走到城市之后继续往西走,大概走多久之后,再往南走,运气好的你就能找到那个地址了(再次手动狗头)。
盘片上也是做了类似的事情,先看个图:
盘片的构造
中间的黑点就是主轴,以主轴为圆心划分了多个磁道(为了方便理解图中只给出了 3 个磁道),每个磁道上又划分出了多个区域,每个区域叫做扇区,并且每个扇区的大小是固定的 512 字节。读取数据的时候,只需要通过这个划分就能够知道数据在哪个磁道、哪个扇区了。
但是通过上图还是能看出一个问题:那就是不同的磁道扇区数是相同的,扇区所在的磁道半径约大,则扇区的面积就越大。但无论面积比靠内磁道的扇区大多少,按照设计、规定只能存储 512 字节的数据,这样一来会浪费大量的存储空间。
为了优化这个问题,就有了 ZBR 技术方案。
ZBR,全称 Zone Bit Recording,用来解决传统盘片的磁道扇区存储空间浪费的问题。它是怎么做的呢?说起来也很简单,越靠外圈磁道的扇区由于面积会更大,所以 ZBR 会放置更多的扇区,从而将空间利用起来。
转换成图形可能就是这样:
盘片的ZBR
不同的磁道扇区数量不同了,外圈磁道上面的扇区会更多些,从而充分的利用空间,提升磁盘的总容量。
存储原理
好,继续深入问题盘片存储相关的问题。
我们知道从宏观上来看,计算机并不会管你是谁,到它这都是 0101010101。那么当读取文件的时候,它是如何从这层磁性材料中识别出来 0101010101,然后还原成我们能看懂的文件的?
前面我们知道盘片上划分了磁道、扇区,相应的磁性材料也同理。现代磁盘就是通过磁化盘片两面的磁性材料来记录数据的,磁性材料序列的改变则代表了对应的二进制 0、1。
磁性序列原理
可以看到,两个磁性 Region 的序列方向不同,则标记为 R(Reverse),相同则标记为 N(No Reverse),当读取的时候,如果探测到序列是 RR,则对应 1,而如果是 NR,则对应 0(或许这就是为什么它叫磁盘吧,再再次手动狗头)
所以,我们常说的写磁盘并不是说读写磁头在盘片上刻东西,而是改变磁性材料的序列,并且读写磁头和盘片没有直接接触,他们有个大概 10 nm 的距离。
并且,从上述现状我们可以简单推导,既然读写磁盘都是靠读取盘片上的磁性序列,并且盘片的两个面都能用于存储数据,那么必然盘片的每个面都有磁头。
磁盘性能
了解完一些简单的原理之后,我们终于可以来了解磁盘性能相关的问题了,我们会深入的分析为什么磁盘 IO 是个非常昂贵的操作。
现在思考一个问题,我们要查询数据,底层会怎么做?是不是会:
将磁头移动到目标文件所在的磁道
此时盘片正被主轴带着旋转,磁头需要等待对应的扇区旋转到磁头这才能读取数据
对应扇区到了之后,就需要等待读取数据&传输
总结一下,磁盘的 IO 请求耗时主要由三部分组成:
- 磁头寻道时间:这个延迟一般在 3-15 ms
- 盘片旋转延迟:这个取决于主轴旋转的速度,随着速度的不同大概在 2-4 ms
- 数据传输时间:这里平均只用 3 微秒,跟上面两个比起来这里的耗时可以忽略不计
这里提到了旋转的问题,在盘片旋转延迟这里,盘片旋转越快,则对应扇区移动到磁头的速度也会越快。
现代磁盘的旋转速度在 5400 或者 7200 RPM(Revolutions Per Minute)不等,当然也有一些高性能的服务器转速会达到 1500 RPM。
盘片旋转延迟的确和转速相关,因为转速越快,对应扇区移动到磁头的位置就越快。但并不是转速越快越好,因为转速越高,发热约严重,磁盘的寿命也就越短。
下面给个不同的转速下对应的旋转延迟的参考:
旋转速度(单位 RPM) | 平均旋转延迟(单位毫秒) |
4800 | 6.25 |
5400 | 5.55 |
7200 | 4.16 |
10000 | 3 |
15000 | 2 |
(以上数据来自 wikipedia)
可能你看到几毫秒觉得还好,并不是那么慢,但是跟内存的速度一对比你就能立马明白。内存的随机读大概在几百纳秒,假设内存的速度是 200 ns、磁盘的速度是 2ms(按上表中转速最高的延迟来算),差了 10000 倍,也就是 4 个数量级。
到这里,我想我们也能理解为什么磁盘的顺序读写能够与内存随机读一战了。因为磁盘顺序读写几乎把前两个最耗时的操作给干掉了,磁头已经移动到了对应的磁道, 也找到了对应的扇区,直接写就完事了。
好了, 关于磁盘的原理就简单介绍到这里。