在本章,我们稍微涉及一些硬件和操作系统层面的事情。
计算机是由硬件和软件组成的,而所有软件的唯一目标就是尽可能最大化的利用下层硬件能够提供的特性,完成上层的功能。
所以才会有人说,硬件是骨头,软件是血肉,骨头决定生物的形态,软件决定生物的神态。不过,依然请放心,我们不会讨论复杂的东西,作为一个软件工程师,也没有人会要求我们去写一个磁盘存储器的硬件驱动代码~在这里,我们只讨论那些为了后面我们理解软件存储而锁需要掌握的硬件知识。
好了,直入主题,硬盘
===硬盘构造介绍===
所谓的数据存储,就是把一串很普通的由0和1组成的字节流按照他原来的顺序写入到一种介质里面去。那么自然而然,使用电驱动的磁铁小针快速的改变可磁化介质从而记录下这些数据就必然是一种很好的选择。
那么,下面就请大家跟我一起来看看磁盘的基本构造:
磁盘的先祖其实就是磁带机,相信阅读本文的读者应该都使用过录音机的(95后无辜的看着我。。。)
从很小的用来听音乐的卡片式磁带机到很大的用来存数据的磁带卷儿,其实样子一直都是这样的(笑)。
在使用的过程中,一般是由一个小电机带着这个磁带向着一个方向转动,然后有一个磁头以很近的距离来读取磁场的微妙变化,从而能够读取到上面记录的数据的。
这里就出现了磁盘中所需要用到的第一个关键的组件,电机,他的主要作用在于给予带动含磁介质向着一个固定的方向转动,从而可以保证数据能够被“顺序”的读出和读入。
然而,当我们尝试把这种磁技术应用于计算机的时候,就立刻发现了一个很重要的问题需要解决:
在计算机的应用场景中,数据的读取可能不完全是顺序的,有可能先读一下开始位置的数据,然后又读一下结果位置的数据,最后又需要读中间位置的数据。并且,这种读取的跳跃过程是无法提前预测的。
因此就有一个问题急需要解决,如何能够让磁介质支持随机访问。
让我们回想一下磁介质写入和读取过程中需要的关键组件:1.磁介质。2.磁头。3.步进电机。
而随机访问则需要能够让磁头与磁介质的特定区段进行接触,从而才能读取到对应的数据。
那么,一种选择是让介质移动到指定位置,磁头不动。一种是让磁头移动到介质的位置上。
明显的,把存储介质移动起来的控制难度要远远大于让磁头移动。
所以,计算机需要的新的磁存储模型就出现了:
磁盘使用步进电机保持匀速运动,然后让磁头移动来读取或写入数据!
不过,虽然磁头移动已经是里面最轻量的玩意儿了,但他仍然需要一个电机带动磁头在磁盘上做寻道操作。
===硬盘块与原子操作===
然后我们再来看另外一个问题,如果你每次写入只写一个bit,那么因为磁盘在高速旋转,有大量的数据传递性工作,导致磁盘需要频繁的等待新的命令,这样会造成磁盘效率非常低下。因此,一次写一批数据就成了合理的选择,所以磁盘一般是按照磁盘块的方式来组织数据的。
常用的块大小是512byte。但因为磁盘的磁头一次只能写一个bit,所以依然会面临断电了数据写一半儿怎么办的问题。。
解决的方法也不会超出大家的预期,这也是计算机能够做出的最大保证了:
如果告诉你写成功了,那一定是写成功了。那失败怎么办?好问题,我们来分析一下:
一台计算机,其实只有三个状态,要么给电机器运转,要么正常关机,要么异常关机。在正常运转状态和正常关机状态的时候,操作系统都可以保证数据的所有操作都是原子的,因为只需要在关机hook上做完该做的事情,同时不允许有新的请求进来就可以了。
只有异常关机的状态略微有点麻烦,首先,因为无论计算机是正常关机还是异常断点的关机,这台计算机在下次给电启动之前都是不可能服务的,所以就算是有个磁盘块只写了一半儿也没什么问题。所以问题就转化成,能否在下次启动并能提供读写服务之前,先把那些写了一半的数据块删掉?(因为没有给请求方反馈过成功,所以这些未完成的块本来就不应该存在)
那下一步如何做就很容易可以想到了。在每次开机的时候判断一下是否是一次正常的关机,如果不是正常关机,那么将那些未被标记为完整写入的块全部删掉。
嗯,这个模式也是贯穿单机有状态存储保证数据一致性的主要方法,可以复用到单机所有需要原子性操作的地方哦~
===读写iops与读写吞吐量(MBPS)与延迟的关系===
这个概念我估计大部分人都会搞混,包括我在内。
所以我也把目前我的理解给到大家
首先
先来界定什么叫做一次io.简单来说,一次io就是应用层发起一次写入或查询的请求
那么这个请求对应到磁盘上面来说呢就是以下几个操作的集合:
1.磁头移动到这次请求所对应的磁道
2.等待硬盘旋转到数据所在的位置
3.读取数据
自然的,如果想增加磁盘的iops数,就需要让磁盘在一秒内尽可能多的完成用户的请求,那么最理想状态下应该是:减少磁头的移动,减少硬盘转到数据所在位置的时间,减少一次请求所要读写的数据块个数。
不过这是个理想状态,因为请求无法预测,所以一般来说也只能是追求尽可能减少随机寻道时间(因为这个是几个iops的参数中影响最大的一个)。
这个指标是面向小数据随机或顺序读写应用时候比较看重,比如数据库。
再来看吞吐量(MBpersecond)
这个指标是磁盘相对比较擅长的指标,他衡量的是数据在单位时间内传出+传入这块磁盘的总数量。
所以如果想增加磁盘的吞吐量指标,就需要让磁盘在一秒内尽可能多的写入或读出数据,那么最理想的状态下应该是:减少磁头的移动,减少磁盘转到数据所在位置的时间,增加一次请求所需要读写的数据块的个数。
比如,如果用户只有一个请求,并且这个请求是要求顺序的将1T的数据写入到磁盘内。这种情况就能发挥出磁盘吞吐量的极限了。
这个指标对于一般的数据库意义不大,但对于视频、搜索引擎、或大文件存储这类顺序读写的应用则比较看重。
延迟
基本上来说,延迟和IOPS是个正比例关系。
为什么这么说呢?原因是更大延迟可以允许计算机做这么一件事,批量处理:
就好比100个旅客要从北京坐飞机到杭州,飞机是个稀缺资源,我们假定北京飞杭州要1个小时。
那么如果一架飞机上只有一个旅客,那么要飞100次才能够把这批旅客运到目的地,运送100个旅客的总时间是100个小时,每小时运送旅客数是100/100=1,而如果要是让先来的旅客等一等,等到100人都做上飞机以后再起飞呢?那么每小时运送的旅客数就是100/乘客的等待时间+1/1约等于100
这样略微增加延迟就可以提升整体的tps量了。不过需要注意的是,这个提升是有上限的,当每架飞机都坐满了人的时候,那么飞机的运力就是最终瓶颈,其他乘客只能等待。
所以一个常见的延迟与请求数的图标往往是这样的:
请求数超过伐值后,就只剩下排队了,系统的运力不可能再有提升了。
====小结===
总结一下磁盘的优势和劣势:
优势:
技术比较成熟,因此价格相对较低
顺序读写因为不涉及到大量的机械寻道,所以吞吐量只和磁盘转速正相关。
劣势:
只要操作需要大量寻道,毕竟寻道是个机械操作,那么磁盘的iops和吞吐量会立刻下降很多。
读取和写入是按照块来进行的,一般块的大小是512bytes,所以一次操作必须一次性的写入这个数量的数据。
嗯下一篇来介绍磁盘raid与阵列