机械硬盘
好像本科时候学的操作系统课程在讲解磁盘的时候非常简略。现在复习一下。
磁盘结构
对于常见的机械磁盘,分磁盘面、磁道、柱面和扇区。
有以下概念 :
磁盘面:磁盘是由一叠磁盘面叠加组合构成,每个磁盘面上都会有一个磁头负责读写。
磁道(Sector/Track):每个盘面会围绕圆心划分出多个同心圆圈,每个圆圈叫做一个磁道。
柱面(Cylinders):所有盘片上的同一位置的磁道组成的立体叫做一个柱面。
扇区(Sector):以磁道为单位管理磁盘仍然太大,所以又把每个磁道划分出了多个扇区。而磁盘存储的最小组成单位就是扇区。
单柱面的存储容量 = 每个扇区的字节数 每柱面扇区数 磁盘面数 。
整体磁盘的容量 = 单柱面容量 * 总的柱面数字。
扇区与扇区之间其实不是紧挨着的,而是在每个扇区结尾还有一个存储纠错码的位置。假设某一个扇区读取时发生了错误,这样在扇区结尾的纠错码就能发现。磁头就会在磁盘下一圈转过来的时候再读取一遍。
linux下查询
查看操作系统挂载的硬盘数量及大小,借助lsblk
命令
然后通过fdisk
可以查看硬盘的详细信息:
1 | fdisk -l /dev/sda |
每个磁道可以存储的数据都是一样的吗?
在老式的磁盘里,确实是每个磁道数据都是一样的。这样越是内圈磁道的存储密度越大。目的就是为了访问方便,通过一个CHS地址:柱面地址(Cylinders)、磁头地址(Heads)、扇区地址(Sectors)直接定位到存储数据所在的扇区。但是这产生的问题就是外圈磁道的数据密度没有充分发挥出来,造成磁盘存储容量很难提升。
现代的磁盘人们改用等密度结构生产硬盘,也就是说,外圈磁道的扇区比内圈磁道多。这种磁盘里扇区是线性编号的,即从0到某个最大值方式排列,并连成一条线。这种寻址模式叫做LBA,全称为Logic Block Address(即扇区的逻辑块地址)。磁盘内部是自己会通过磁盘控制器来完成CHS到LBA的转换,进而定位到具体的物理扇区
物理扇区大小
现代科技进步了,磁盘底层的最小组成单位并不是扇区512字节,physical Sector size 4KB。但这时存在一个问题是扇区大小为512字节的假设已经贯穿于整个软件链,比如BIOS,启动加载器,操作系统内核,文件系统代码,以及磁盘工具,等等。直接切换到4096 byte兼容性问题太大了,所以每个新的磁盘控制器将4096字节的物理扇区对应成了8个512字节的逻辑扇区,兼容各种老软件。
除了fdisk -l
命令外,如下方式也可以查看物理/逻辑扇区大小。
1 | cat /sys/block/sda/queue/physical_block_size |
磁头的数量
磁盘不可能真的装很多磁头,通过fdisk -l
看到的磁头数量和扇区以及磁道一样,是被虚拟出来的。
磁盘分区
分区是操作系统对磁盘进行管理的第一步,这也是任何一个计算机使用者都非常熟悉的概念。例如Windows下的C、D、E、F盘。那么操作系统的设计者是如何把整块磁盘分成C、D等分区的?
为了方便讨论,这里假设要分的硬盘是有50个盘面,3000个柱面。给出两种方案
- 方案一:50个盘面,C盘是0-10盘面, D盘是10-20个盘面,……
- 方案二:3263个柱面,C盘0-1000个柱面,D盘1001-2001个柱面,……
接下来讨论下那种方案更优秀,这得从磁盘的读写延时角度说起。读写原理说起来也简单,就是磁头要找到指定的磁道,指定的扇区,进而把数据读取出来或者写入进去的过程。这个过程分成如下三步:
- 第一步,首先是磁头径向移动来寻找数据所在的磁道。这部分时间叫寻道时间。寻道时间,现代磁盘大概在3-15ms,其中寻道时间大小主要受磁头当前所在位置和目标磁道所在位置相对距离的影响
- 第二步,找到目标磁道后通过盘面旋转,将目标扇区移动到磁头的正下方,这部分时间叫旋转延迟。现在主流服务器上经常使用的是1W转/分钟的磁盘,每旋转一周所需的时间为60*1000/10000=6ms,故其旋转延迟为(0-6ms)
- 第三步,向目标扇区读取或者写入数据,这部分时间叫存取时间。这个是电磁操作,所以一般耗时较短,为零点几ms。
到此为止,单次磁盘IO时间 = 寻道时间 + 旋转延迟 + 存取时间
分区上采用哪一种方案,最主要看的是那种方式性能更快。在磁盘分区的使用中,存在一个基本事实,那就是同一分区下的数据经常会一起读取。两种方案的对于旋转延迟、和存取时间上表现的性能是一样的,主要区别是在寻道时间的表现上:
假如采用第一种,那么这样磁头就需要在3000多个磁道间不停地跳来跳去,这样磁盘的寻道时间就降不下来。而对于方案二,假如对于磁盘C,只需要在磁头在1-1000个磁道间移动就可以了,大大降低了寻道时间。所以所有的操作系统采用的都是方案二,没有用方案一的。
分区的过程就是输入起始柱面号和截至柱面号的过程。不过在实际中,分区并不能从0号柱面开始的,因为磁盘的第一个磁道对应的柱面会被用来安装引导加载程序以及磁盘分区表。所以,操作系统通过按磁道对应的柱面划分分区,来降低磁盘IO所花费的的寻道时间 ,最终提高磁盘的读写性能。
机械硬盘的缺点及解决办法
主要问题
机械硬盘更多是用机械技术做出来的产品。当把带有机械技术基因的磁盘搭到计算机,尤其是应用到服务器领域的时候,暴露出了机械技术的两个严重问题:
第一,速度慢。如果把内存和CPU的速度比作汽车和飞机的话,机械硬盘毫秒级别的延迟几乎就是牛车级别的。
第二,容易坏。经常听说谁谁的磁盘坏了,很少有听说过谁的内存条,CPU坏了。
要想保证服务器运转的稳定和高速,就必须解决硬盘的这两个缺陷。
解决办法
多硬盘连接
单块硬盘不行,尝试同时使用多块硬盘。但假如给了N块硬盘,如何设计一个使用的方案?
- RAID 0:把一个文件分成N片,每一片都散列在不同的硬盘上。这样当文件进行读取的时候,就可以N块硬盘一起来工作,从而达到读取速度提高到N倍的效果。
缺点:没有解决容易坏的问题,任何一块硬盘坏了都会导致存储系统故障。
- RAID 1:仍然把文件分片,但是所有的分片都存在一块硬盘上,其它的硬盘只存拷贝。这既提高了硬盘的访问速度,也解决了坏的问题。任意一块硬盘坏了,存储系统都可以正常使用,只不过速度会打一点折扣。
缺点:实现成本高。
- RAID 5:样要对文件进行分片,但是不对存储的数据进行备份,而是会再单独存一个校验数据片。假如文件分为A1 A2 A3,然后需要再存一个校验片到别的磁盘上。这样不管A1,A2还是A3那一片丢失了,都可以根据另外两片和校验片合成出来。既保证了数据的安全性,又只用了一块磁盘做冗余存储。
假如有8块256GB的硬盘,那么RAID5方案下的磁盘阵列从用户角度来看可用的存储空间是7*256GB,只“浪费”了一块盘的空间,所以目前RAID5应用比较广泛。
RAID卡缓存
硬盘延迟是毫秒级别的,即使是多快硬盘并行,也只能提升数倍而已,不能够达到量级的提升。和CPU内存的纳秒级别工作频率比起来,还是太慢。在计算机界,没有缓存解决不了的速度问题,如果有,那就再加一层。现代磁盘本身也基本都带了缓存,另外在一些比较新的raid卡里,硬件开发者们又搞出来了一层“内存”,并且还自己附带一块电池,这就是RAID卡缓存。几款主流RAID卡的配置:
PERC S120 入门软件阵列卡,主板集成无缓存 支持RAID 0 1
PERC H330 入门硬件RAID卡,无板载缓存, 支持RAID 0 1 5 10 50
- PERC H730 主流硬件RAID卡带有1G缓存和电池 支持RAID 0 1 5 6 10 50 60
- PERC H730P 高性能硬件RAID卡带有2G缓存和电池 支持RAID 0 1 5 6 10 50 60
- PERC H830 同H730P,没有内置接口,使用外置接口连接附加存储磁盘柜用
拿目前服务器端出镜率比较高的H730和H730P来看,他们分别带了1G和2G的缓存卡,并且自带电池。电池的作用就是当发现主机意外断电的时候,能够快速把缓存中的数据写回到磁盘中去。对于写入,一般操作系统写到这个RAID卡里就完事了,所以速度快。对于读取也是,只要缓存里有,就不会透传到磁盘的机械轴上。
文件相关函数里设置DIRECT I/O仅仅只能绕开操作系统本身的Page Cache,而RAID卡里的缓存,对于Linux来说,可以说算是一个黑盒。换句话说,就是操作系统并不清楚RAID卡是从缓存里吐的数据,还是真正从硬盘里读的。