掌握聚合最新动态了解行业最新趋势
API接口,开发服务,免费咨询服务

我是一块硬盘



我知道CPU和内存是计算机的核心, 毕竟所有的运算最后都得通过他们俩来完成, CPU从内存里要取一条指令, 做计算,然后再写回内存, 如此周而复始。

但是这俩货却瞧不起我,说这是什么年代了,还在用机械式操作, 读写数据的时候, 还得一个磁头在多个盘片上滑来滑去,找来找去, 速度慢的要死。


内存说:“CPU比我快100倍, 比你快100万倍,整个系统的速度都被你给拖慢了。”

这是典型的五十步笑百步。

他俩还嘲笑我很娇气,得真空、密闭、不能有浮尘、运行时不能震动, 一动就坏了。

但这俩二货总是会忘记他俩的最大问题,所以我只用一句就把他们俩给噎死: 你们俩断电了怎么办?

还有我的容量都是按TB, 甚至PB 来算的, 就你们俩那点容量,还笑我?

还有,没有我来存储程序,你们从哪儿得到程序, 难道要像牵牛星(如下图)一样, 手工拨动一排开关来输入程序吗?

其实我也很纳闷,  为什么你们人类造不出来一个能够断电存储的, 大容量的访问速度快的,当然还要便宜的硬盘来 ,你们不都上天了吗?要登陆火星了吗? 这些基础的材料怎么还无法突破?

我憧憬着这么一天的来临, 如果能制造出来了, CPU就可以直接访问硬盘了, 内存就一边凉快去吧。

在制造出来之前, 你们必须得容忍CPU-内存-硬盘之间的速度不匹配, 并且想出办法来解决这种速度的不匹配, 比如用缓存、 直接内存访问、 多进程/线程切换等等方法。

内部结构


其实我的内部是长这个样子的:


看到没有,我有很多个盘片像串糖葫芦一样被串在一个主轴上, 主轴带着他们疯狂的旋转。 

每个盘片都有很多一圈一圈的磁道, 每个磁道又分为一个一个的扇区。

多个盘片上的同一位置的磁道组成了一个柱面 (需要发挥一下你的想象力)

最后每个盘片上都有可以读写数据的磁头。所以,如果你想访问我的数据,可以说: 把0柱面, 0磁头, 1扇区的数据给我拿来。 

我就把磁头挪到您指定的柱面,对每个磁盘来讲其实就是指定的磁道, 所以这叫“寻道时间

然后再旋转磁盘,让磁头指向您指定的扇区,这才能开始读取数据, 这叫“旋转时间”,转速快的硬盘能更快的旋转到特定扇区, 所以性能会更好些。

文件


当然,对于绝大部分人来说,都不想去了解什么柱面,磁头,扇区这些非人的术语,所以我为懒人们专门提供了一个叫做逻辑块的方式,你看到磁盘就是有一个个“块”组成的,编号为1, 2, 3, ..n 。

想取哪一块就取哪一块, 比如你说:把第1024号的“块" 的数据给我取过来, 我在内部就把1024转化成柱面,磁头,扇区, 按照上面说的方法寻道,旋转,读取数据。

但是这还远远不够,比方说你想写个文档,输入了很多字和图片,最后想存到我这个硬盘上,你该怎么操作?

一种方法是这样的:: 硬盘,给我找20个空闲的磁盘块, 我想存我的文档

:空闲的磁盘块编号是1024, 2048, 2049 ,3000 ,......

: 把这些文字和图片存到这些磁盘块上

: 好的,存完了, 你得记住这些块啊, 这样下次才能读取。

: 拿一支笔把这些磁盘块编号都记到本子上

过了几天......

: 硬盘, 把1024,2048,2049,3000这些数据给我取出来,我要编辑。

: 好的,这是你的数据

没有人喜欢这种方式, 太折磨人了!每个人喜欢这么做:   打开word -> 新建一个文件-> 输入文字和图片-> 保存到C盘“我的文档”目录下。

这个所谓的“文件”和“目录”就是我的杰作啊,你再也不需要和烦人的磁盘块打交道, 只需要记住你的文件名和路径, 一切工作交由我和操作系统老大来搞定。

我和老大商量好了,文件对人类来说是最小存储单位, 你想存任何东西,无论多么小,非得建个文件不可。

此外为了让这个世界整洁有序, 多个文件可以放到一个目录(其实也是个特殊的文件)里, 目录之上还可以有目录,形成一个树的结构。

文件这个东西是个伟大的发明, 我估计你们还得再用100年。

文件的存放


我日常的主要工作就是对目录和文件做操作,当然需要操作系统老大的配合,好吧,其实是老大在主导。

这其中最重要的一个问题怎么去记录各个文件都用到哪些磁盘块?

内存给我支了一招:你可以采用连续记录的方式啊, 就像这样。


  • 文件1 占据磁盘块 1-3
  • 文件2 占据磁盘块 8-12
  • 文件3 占据磁盘块 15-20

内存说: 这种方法在随机访问文件是效率极好,因为你只要知道了开头和长度,就像数组一样可以随便访问, 就像CPU访问我一样, 只要给出地址,立刻就能定位到指定的位置。

我仔细想了想, 内存出的是一个损招, 比如说内存磁盘块 4 -7 ,以及13-14怎么没用?  

那是因为之前那里也有文件,后来被删除了,留下了空洞, 如果之后没有大小合适的文件过来,他们就永远空在那里了。

对我来说这是严重的浪费, 这是我不能容忍的。 

我说:“小样你以为我看不出来啊,你不就是嫉妒我容量大,让我浪费一点嘛”

内存坏笑了一下又说: 不喜欢也没关系嘛,试试采用链式啊:


这个文件从第一块磁盘开始,形成一个链 1->9->18->8->3   , 每一块空闲的磁盘都会得到充分的利用, 效率非常高。

我心想: 这些码农说的数据结构和算法还真是有用啊, 这里也用上链表了。

可是这种方式随机的访问效果太差, 每次都得从第一块开始,沿着绳子往后找,太痛苦了。

现在内存已经嘲笑我慢了,用这种很慢的办法,还不得笑死我?

操作系统老大说:“别听内存在那里BB了, 用索引式!”


例如第16号磁盘块专门用来存放文件属性以及该文件所使用的磁盘块。

老大把这个磁盘块叫做inode,通过它可以轻松的找到这个文件所使用的所有磁盘块, 无论是顺序访问还是随机访问都很快。

唯一的缺点是得用额外的磁盘块单独存放inode 。

我觉得挺好,没有十全十美的东西,折中达到平衡最重要 ! 就是它了!

目录


我问老大: 每个文件都需要有个inode来描述,  每个目录是不是也需要一个? 

”这是自然,和文件一样, 每个目录也是一个inode,  其中有目录的属性,还有存放这个目录内容的磁盘块号,在磁盘块中才真正的存放着目录下的内容“

“举个例子来说吧: 有人要读取  /tmp/test.log  这个文件, 查找次序是这样的:根目录inode->根目录磁盘块->tmp目录inode->tmp目录磁盘块->test.log的 inode->读取磁盘块”


内存说: “我赛,这也太绕了吧,比CPU访问我的数据麻烦多了, 硬盘,你要小心点, 这要是操作不当的很容易出乱子的。”

我心想内存这次没坑我,他提醒的对, 这操作确实有点复杂,读数据的时候还行, 如果是修改,尤其是删除就很容易出事,例如想删除上面的文件/tmp/test.log,

需要这些步骤:

  • (1) 在目录中删除文件
  • (2) 释放inode 到空闲的节点池, 这样可以复用
  • (3) 将磁盘块释放到空闲的磁盘块池

在操作某一步的时候出现系统崩溃,那我这些个目录和文件就凌乱了, 可能会出现空间无法释放的情况。 

老大说: “这确实比较烦, 不过也能解决,听说过数据库是怎么办的吗: 记录日志! ”

”就是把要做的事记录下来?“

“是的, 在做操作之前, 记录要做的事情,形成日志, 把他们成功写入磁盘以后再正式动手操作,  等到所有步骤都搞完,才可以擦除日志项。  你想想,如果执行到某一步崩溃, 系统重启时检查日志项,就知道哪些没做,哪些已经做了, 对于没做的日志,重新来一遍就是了” 。

其实说的很轻松,实施起来还是挺难的, 重新执行就意味着那些操作一定是可以重复执行, 并且不会带来破坏才行。 (码农翻身注:这叫做日志(Journal)文件系统)

管理空闲块


目录和文件的存储问题解决了, 接下来我需要一个大管家,把那些没有使用的、空白的、数量上亿的磁盘块给管理起来,只有这样, 新的文件来的时候,才能分配空间存储。

操作系统老大给我推荐了两位, 第一位主张是链式大法好, 无非就是把空闲磁盘块组成一个链表(又是链表!) ,但是我心里盘算了一下: 如果磁盘块号是32位的,每个块都得花费我32位的空间,如果我有5亿个空闲块, 那仅仅为了记录他们就要占用接近2G的磁盘空间!  这浪费可是有点大啊。

还有一位主张位图法, 这个方法更简单, 对每个磁盘块,如果已经被使用,那就标记为1,   没被使用就是0。 这样整个磁盘块就形成了一个由0和1组成的一个大位图。

由于每个磁盘块只用一个位来表示, 非常节省空间, 这个方案我喜欢!

文件系统


扯了这么多,是时候看一看全局了, 在你们程序员的眼中, 其实我是长这个样子的(拿你们崇拜的Linux ext2为例):


我这个硬盘主要由MBR(Master Boot Record)和各个磁盘分区组成。

MBR中的有 引导代码 和 磁盘分区表,  分区表中记录了每个分区的起始位置,以及哪个磁盘分区是活动分区,  这样系统就会找到它, 然后装载这个分区中的引导块,并执行之。

引导块将会装载存存储在本分区的操作系统。  需要注意的是,每个分区都有一个引导块,不管这个分区有没有操作系统,这是各大厂商的约定,是一种标准。 

每个分区除了必须的引导块之外,又被分成多个块组。

在每个块组中你能看到熟悉的磁盘块位图和inode位图, 不用解释估计你也知道是干嘛的。还有inode表(当然是存放文件和目录的inode 了)和真正的数据块。 

对了, 我的磁盘分区表只有64个字节, 而每个分区项占用16个字节, 所以只能容纳4个分区。 如果你想用多于4个分区, 你就需要把其中一个设为扩展分区, 然后在其中继续划分成逻辑分区,想划几个就划分几个。

一般情况下,大家都喜欢把我划分成一个主分区+一个扩展分区,   在扩展分区中再需要划分。



本文已获作者授权,如需转载请与作者联系

你看到的只是冰山一角, 更多精彩文章,尽在“码农翻身” 微信公众号, 回复消息"m"或"目录" 查看更多文章

有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan  QQ: 14703250

我是一个线程

我是一个Java class

Javascript: 一个屌丝的逆袭

Java : 一个帝国的诞生

我是一个网卡

我是一个路由器

我是一个进程

TCP/IP 之 大明王朝的邮差

CPU 阿甘

CPU 阿甘之烦恼

Basic : 一个老兵的自述

小王的架构师之路

编程的自学方法

程序员在工作中必备的能力

码农需要知道的潜规则

IE为什么把Chrome和火狐打伤了

Node.js :我只需要一个店小二

假如我是计算机系老师

假如时光倒流,我会这么学Java

学会编程,而不是学会Java

15年编程生涯,资深架构师总结的7条经验

你看到的只是冰山一角, 更多精彩文章,尽在“码农翻身” 微信公众号, 回复消息"m"或"目录" 查看更多文章

有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan  QQ: 14703250


公众号:码农翻身“码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。推荐一个叫掘金的开发者社区,很多技术干货,  我的文章也会在这里分享 : 

 

声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com

0512-88869195
数 据 驱 动 未 来
Data Drives The Future