操作系统の磁盘存储器管理全解让最慢的家伙跑得快一点你有没有想过为什么你的电脑有时候会卡一下尤其是打开一个大文件或者启动一个大型游戏的时候明明CPU在GHz级别狂跑却还是要等上好几秒答案很简单——CPU在等磁盘。在计算机的所有部件中磁盘是那个拖后腿的速度比内存慢几百万倍。怎么让这个最慢的家伙尽量跑得快一点就是磁盘存储器管理要解决的核心问题。这篇文章我们把操作系统中关于磁盘管理的知识从头到尾扒个干净——从磁盘长啥样、读写一次要多久、到怎么调度请求、怎么分配空间、怎么格式化、怎么提速、怎么搞RAID一个都不落。坐稳了发车。本文目录磁盘存储器概述存储界的阶级划分磁盘的物理结构与访问时间一次读写到底要多久磁盘调度算法排队也得讲策略外存分配方式文件在磁盘上怎么摆磁盘空间管理谁占着地谁空着磁盘格式化新硬盘到手怎么从白板变可用磁盘高速缓存用内存帮磁盘打辅助提高磁盘I/O速度的方法各种加速骚操作RAID多块盘组队又快又稳一、磁盘存储器概述存储界的阶级划分1.1 存储层次计算机的存储不是扁平的它是一个清晰的金字塔结构。从上到下依次为寄存器→高速缓存Cache→主存内存/RAM→磁盘HDD/SSD→磁带/光盘。存储层次结构速度、容量与价格的权衡越往上速度越快、容量越小、价格越贵。寄存器在CPU内部访问速度是皮秒级Cache也是芯片级的纳秒级主存内存条也是纳秒级但比Cache慢几倍磁盘是毫秒级——比内存慢了几百万倍。磁带和光盘更慢但胜在容量极大、价格极低主要用来做归档和备份。磁盘属于辅助存储器外存——CPU不能直接访问外存中的数据必须先把数据读到内存里CPU才能处理。所以磁盘和内存之间的数据搬运效率直接决定了整个系统的体感速度。1.2 磁盘的分类硬盘驱动器HDD——传统的机械硬盘也叫温切斯特磁盘Winchester Disk。内部有盘片在旋转、磁头在寻道是纯机械结构。优点是容量大、价格低缺点是速度慢毫秒级、怕震动。固态硬盘SSD——基于闪存Flash Memory没有机械部件。随机访问速度远快于HDD微秒级抗震性好。缺点是写入有寿命限制闪存有擦写次数上限一般几千到几万次价格较高但在持续下降。磁带——顺序存取设备不能随机访问。容量极大单盘可达数十TB价格极低。主要用于企业级归档和冷数据备份。你不会在日常使用中直接接触磁带但很多大公司的数据中心里堆满了磁带柜。光盘——包括CD700MB、DVD4.7~17GB、蓝光25~100GB。有只读型ROM、一次写入型R和可重写型RW三种。现在用得越来越少了但在软件分发和影音领域还有一席之地。1.3 磁盘设备的特点磁盘不管是HDD还是SSD有几个共同特点它是块设备——以块扇区为单位进行读写不是像键盘那样一个字符一个字符地传。它可随机访问——可以直接跳到任意块不需要从头开始。它是共享设备——多个进程可以交替使用同一块磁盘。最关键的是它速度远慢于主存——毫秒 vs 纳秒差了六个数量级。二、磁盘的物理结构与访问时间一次读写到底要多久2.1 磁盘的物理结构磁盘的物理结构盘面、磁道、柱面与扇区传统机械硬盘HDD的物理结构可以用几个关键词来概括盘面Platter——磁盘由多个盘片叠在一起每个盘片有上下两个面每个面都能存数据。每个盘面配有一个磁头Head负责读写数据。所有磁头安装在一个共同的臂上同时移动——也就是说所有磁头永远在同一个柱面上。磁道Track——盘面上划了一圈一圈的同心圆每一圈就是一个磁道。外圈的磁道比内圈长在现代磁盘中外圈磁道可能有更多的扇区。柱面Cylinder——所有盘面上相同位置的磁道组成一个柱面。柱面数 每面的磁道数。寻道的时候磁头一起移动到一个柱面然后选择对应的磁头来读写。扇区Sector——每个磁道被分成若干段每段就是一个扇区。扇区是磁盘最小的读写单位。传统扇区大小是512字节现代磁盘采用高级格式化Advanced Format扇区大小为4KB。要定位磁盘上的某一块数据需要三个坐标柱面号 磁头号 扇区号这叫CHS寻址Cylinder-Head-Sector。现代磁盘更多使用LBA逻辑块寻址——把所有扇区编成连续的线性地址0, 1, 2, 3...由磁盘控制器内部负责LBA到CHS的转换。2.2 磁盘访问时间磁盘访问时间的三个组成部分读写一个磁盘块需要的时间由三部分组成寻道时间Seek Time——磁头从当前磁道移动到目标磁道的时间。这是最耗时的部分因为涉及机械运动磁头物理移动。寻道时间 启动时间 移动时间 减速时间。典型硬盘的平均寻道时间在5~10毫秒。旋转延迟Rotational Latency——磁头到达目标磁道了但目标扇区可能还没转到磁头下面。需要等盘片转一转。平均旋转延迟 1/(2 × 转速)。7200转/分的硬盘转一圈约8.33毫秒平均旋转延迟约4.17毫秒。15000转的企业级硬盘平均旋转延迟约2毫秒。传输时间Transfer Time——扇区转到磁头下面后实际读写数据的时间。通常很短在微秒级别。总访问时间 T 寻道时间 旋转延迟 传输时间。由于寻道时间占比最大所以磁盘调度算法的核心目标就是减少寻道时间——让磁头尽量少跑、跑短路。2.3 磁盘的I/O请求进程发出的磁盘I/O请求通常包含以下信息进程标识谁发的、操作类型读还是写、数据在内存中的起始地址数据搬到内存哪/从内存哪搬来、数据在磁盘上的起始位置柱面号、磁头号、扇区号、传输的数据量要读写多少个扇区。多个I/O请求会排队等待服务形成一个请求队列。磁盘调度算法就是决定先服务队列中的哪个请求的策略。三、磁盘调度算法排队也得讲策略磁盘调度算法对比不同策略的磁头移动轨迹假设有多个读写请求在排队先服务哪个不同的策略就是不同的调度算法。调度的目标有三个减少平均寻道时间、提高I/O吞吐量、保证公平性避免饥饿。3.1 FCFS先来先服务最简单的策略谁先来谁先被服务。优点是完全公平不会有饥饿问题。缺点是完全不考虑磁头当前位置磁头可能在磁盘上来回乱跑寻道距离很长。平均寻道时间是所有算法中最长的。就像餐厅叫号完全按顺序来不管你坐在哪个位置服务员得满场跑。3.2 SSTF最短寻道时间优先每次选离当前磁头位置最近的请求。效率比FCFS高很多——磁头尽量就近服务减少了大量不必要的移动。但有一个致命缺陷可能导致饥饿。远处的请求可能一直等不到因为总有更近的新请求插队。这就像一个贪心算法——每一步都选当前最优但不保证全局最优。3.3 SCAN扫描算法/电梯算法磁头像电梯一样工作单方向一路扫过去沿途服务所有请求扫到磁盘一端后反向继续扫。就像电梯从1楼上到顶楼再从顶楼下到1楼。优点无饥饿——每个请求最多等一个完整的来回电梯总会扫到你那一层。缺点是两端服务密度不均匀——靠近端点的请求等待时间更长因为磁头要到端点才掉头。另外磁头刚扫过的方向上新来的请求要等整个回程才能被服务。3.4 C-SCAN循环扫描磁头只在一个方向上服务请求比如从左到右到达一端后直接跳回起点回程不服务任何请求然后重新开始。好处是等待时间更均匀——每个请求最多等一个完整的单向扫描周期。坏处是回跳那一段浪费了时间空跑。适合请求分布比较均匀的场景。3.5 LOOK算法SCAN的改良版。磁头不需要扫到磁盘最末端——如果在当前方向上已经没有更多请求了就立即反向。减少了不必要的空跑。就像电梯不会非要到顶楼才掉头如果最高只到15楼有人按了按钮到了15楼就掉头往下。3.6 C-LOOK算法C-SCAN的LOOK版。单方向扫描当前方向没有请求了就跳回最远端的请求位置继续。等待时间均匀且减少了空跑。3.7 N步SCAN把请求队列按时间分为N段子队列每个子队列内部用SCAN算法。正在服务的子队列中新加入的请求放到下一个子队列里。这样做的目的是防止磁臂粘着——某个进程不断发请求霸占磁头导致其他进程饿死。3.8 FSCAN两队列扫描N步SCAN的简化版N全部当前请求。维护两个队列当前服务队列和新请求队列。当前队列服务期间新来的请求都进入新请求队列。当前队列服务完后两个队列交换。效果与N步SCAN类似。3.9 算法对比总结算法公平性平均寻道饥饿特点FCFS最公平最长无简单但效率最低SSTF不公平较短可能贪心策略可能饥饿SCAN较公平中等无电梯算法两端不均C-SCAN较公平中等无等待更均匀LOOK较公平较短无SCAN的优化版C-LOOK较公平较短无C-SCAN的优化版N步SCAN公平中等无防磁臂粘着FSCAN公平中等无N步SCAN简化版四、外存分配方式文件在磁盘上怎么摆外存分配方式对比连续、链接与索引文件的各个数据块在磁盘上怎么存放不同的方式有不同的优缺点。4.1 连续分配文件的各个部分占据连续的物理块。目录项中只需要记录起始块号 块数就能定位文件的所有数据。优点是顺序访问速度极快磁头不用跑来跑去也支持直接访问第N块 起始块号 N直接算。缺点是产生外部碎片删除文件后留下的空隙可能太小放不下新的大文件而且文件不易动态增长后面的位置可能已经被其他文件占了。需要提前知道文件大小或者预分配过多空间造成浪费。4.2 链接分配文件不需要占据连续的物理块而是通过指针链接在一起。隐式链接——每个物理块的末尾存一个指向下一个块的指针。目录项只记录起始块号。优点是无外部碎片文件容易扩展。缺点是只适合顺序访问想找第100块得从第1块跟着指针一步步走而且可靠性差——中间某个块的指针坏了链子就断了。显式链接FAT——把链接指针从数据块中抽出来集中存放在内存里的一张文件分配表FAT中。想找下一个块查FAT表就行。这样既支持直接访问又提高了检索速度。缺点是FAT表本身要占内存磁盘越大表越大。FAT16/FAT32/exFAT都用这种方式。4.3 索引分配为每个文件建一张索引表记录文件各部分对应的物理块号。目录项记录索引表的地址。想找第N块查索引表直接跳到对应物理块。优点是支持直接访问无外部碎片。缺点是索引表本身也占空间。大文件的处理方案链接索引——多个索引块用指针链接起来。多级索引——一级索引指向数据块二级索引指向一级索引块三级索引指向二级索引块。混合索引Unix inode方式——inode中直接存放一部分数据块号如10个直接地址然后有一次间接、二次间接、三次间接。小文件走直接地址大文件走间接地址灵活高效。4.4 分配方式对比分配方式顺序访问直接访问外部碎片文件扩展额外开销连续分配快支持有困难无隐式链接快不支持无容易指针空间显式链接(FAT)快支持无容易FAT表占内存索引分配快支持无容易索引表空间五、磁盘空间管理谁占着地谁空着磁盘空间管理四种方法对比磁盘空间是有限的。文件系统需要知道哪些块是空闲的、哪些已经被占了。有四种经典的管理方法5.1 空闲表法最直观的方式用一张表记录所有空闲区的起始块号和空闲块数。比如从第100块开始有5块空闲从第200块开始有10块空闲。分配时查表找合适的空闲区回收时把归还的块登记回表并合并相邻的空闲区。优点是简单直观适合连续分配。缺点是空闲区太多时表会很大——磁盘碎片化严重的话可能有成千上万个小空闲区。5.2 空闲链表法把空闲块用指针链接成链表。有两种变体空闲块链——每个空闲块单独链接一个接一个。空闲盘区链——把连续的空闲区作为一个整体来链接每个结点记录起始块号 块数 指针减少链表长度。优点是分配和回收方便——从链头取块就是分配把块插回链中就是回收。缺点是链接指针本身也占空间。5.3 位示图法Bitmap用一个二进制位数组表示每个磁盘块的状态0空闲1已分配。1000块的磁盘位示图只需要125字节1000 ÷ 8。优点非常明显占用空间极小、容易找到连续空闲块找连续的0就行了、整个位图可以常驻内存。广泛用于各种现代文件系统。5.4 成组链接法Unix/Linux的经典方式。核心思想空闲块分组每组最多N块如50块。每组的第一块存放下一组的块数和块号。超级块保存当前组的空闲块列表。分配时从当前组取一块。当前组取完了加载下一组信息到超级块。回收时把块放回当前组。当前组满了形成新组。当前组空了加载下一组。大多数操作只需要读写超级块不需要遍历整个磁盘所以很快。六、磁盘格式化新硬盘到手怎么从白板变可用磁盘格式化从物理格式化到逻辑格式化的三个步骤一块全新的硬盘不能直接存文件需要经历三个步骤才能被操作系统使用6.1 低级格式化物理格式化在磁盘上划分磁道和扇区写入扇区头信息标识磁道号和扇区号、数据区和校验码ECC。同时标记坏扇区缺陷列表让系统知道这些位置不能用。这一步由硬盘厂商在出厂时完成——你买到的硬盘已经低级格式化好了。用户一般不需要也不应该自己做低级格式化。6.2 分区把磁盘划分为若干逻辑分区。每个分区可以独立管理使用不同的文件系统。分区过程中会写入主引导记录MBR和分区表告诉系统这块磁盘有几个区每个区从哪到哪。传统MBR分区方式有局限最多4个主分区最大支持2TB磁盘。现代系统使用GPTGUID分区表作为替代方案支持更大磁盘2TB、更多分区、分区表有备份更可靠。6.3 高级格式化逻辑格式化在分区上创建文件系统。具体包括写入引导块Boot Block用于系统启动、写入超级块Superblock记录文件系统整体信息、创建inode表索引节点表、创建根目录、初始化空闲空间管理结构位图或成组链接等。这一步完成后操作系统才能在这个分区上创建和管理文件。你在Windows上右键格式化U盘做的就是这一步。七、磁盘高速缓存用内存帮磁盘打辅助7.1 缓存原理和CPU缓存的思路完全一样用快速的内存来缓存最近访问过的磁盘数据。因为内存比磁盘快百万倍如果后续访问的数据在缓存中命中就不需要再访问磁盘了。这利用了局部性原理——时间局部性最近访问的数据很可能再次被访问和空间局部性访问了某块数据后很可能接着访问相邻的块。7.2 缓冲区的三种状态缓存中的缓冲区分为三种自由缓冲Free——还没被使用随时可以被分配。清洁缓冲Clean——已缓存磁盘数据且内容和磁盘一致没被修改过。脏缓冲Dirty——内容被修改过和磁盘不一致需要找机会写回磁盘。7.3 置换策略缓存满了怎么办需要淘汰一些缓冲区。常用策略LRU最近最少使用——淘汰最久没被访问的。LFU最少使用——淘汰访问次数最少的。FIFO先进先出——最早进入缓存的先淘汰。Clock算法时钟算法——LRU的近似实现用一个循环链表和引用位来模拟。7.4 写策略写操作有三种策略写穿Write-through——每次写缓存的同时也写磁盘。数据安全但写性能差每次写都要等磁盘。写回Write-back——只写缓存标记为脏。缓冲区被置换出时才写回磁盘。性能好但有断电丢数据的风险。周期写盘——定期比如每隔几秒把所有脏缓冲写回磁盘。这是折中方案兼顾性能和安全性。Linux的sync命令和内核的 flush 线程就是干这个的。7.5 统一缓冲池现代操作系统将磁盘缓存和文件系统的缓冲区统一管理形成统一的缓冲池。Linux的Page Cache就是这种实现——所有磁盘数据文件数据、目录数据、inode数据都通过Page Cache来缓存和管理。八、提高磁盘I/O速度的方法各种加速骚操作磁盘是系统中最慢的部件之一操作系统绞尽脑汁想出了各种加速手段8.1 提前读Read-ahead当系统检测到你在顺序读取一个文件时它会猜到你接下来可能要读后面的数据于是提前把后续的数据读到缓存中。这样你真正要读的时候数据已经在缓存里了命中不用等磁盘。提前读对顺序访问效果非常好看视频、读大文件但对随机访问基本没用。Linux的预读窗口大小是自适应的——连续命中时窗口越来越大频繁不命中时窗口缩小。8.2 延迟写Delayed Write写操作不立即写磁盘而是先写到缓存中标记为脏然后在适当的时候统一写回。好处是可以合并多次小写为一次大写——比如你连续修改一个文件10次如果每次都写磁盘就要写10次有了延迟写可能只需要写1次。Linux中有专门的pdflush/flush线程定期把脏页写回磁盘。但风险是断电可能丢数据——还没写回的脏页会丢失。所以重要的程序会用fsync()系统调用强制立即写盘。8.3 优化文件物理块分布让同一个文件的各个块尽量在磁盘上连续存放减少寻道次数。ext4的区段extent分配就是这个思路——用起始块号连续块数来表示一段连续的数据块而不是逐块记录。预分配——创建文件时预先分配一定的连续空间避免后续频繁扩展导致文件块分散。8.4 减少磁头移动通过合理的磁盘调度算法SCAN、C-SCAN等将同一柱面的请求集中处理减少不必要的寻道。在多磁盘环境下还可以将I/O负载分散到多块磁盘上。8.5 NCQ原生命令队列这是SATA硬盘的一个硬件特性。操作系统只管往硬盘发I/O请求硬盘内部自己会对请求重新排序优化磁头的移动路径。相当于把调度算法从操作系统层下沉到了硬件层。操作系统只需要发出请求硬盘自己决定执行顺序。8.6 Linux的I/O调度器Linux内核提供了几种I/O调度器CFQ完全公平队列——为每个进程分配独立的I/O时间片保证公平。Deadline截止时间调度——为每个请求设定截止时间防止饥饿。NOOP无操作/直通——不做任何调度直接按FIFO顺序执行。BFQ预算公平队列——CFQ的改进版按预算分配I/O资源。SSD通常使用NOOP或Deadline——因为SSD没有机械寻道不需要像HDD那样优化磁头移动路径调度器的开销反而可能成为瓶颈。九、RAID多块盘组队又快又稳RAID级别大比拼速度、可靠性与成本的权衡RAIDRedundant Array of Independent Disks廉价冗余磁盘阵列用多块磁盘组合成一个逻辑磁盘目的是提高性能和/或可靠性。两个核心概念数据条带化Striping——数据分散到多盘并行读写提速。冗余Redundancy——额外存储校验信息某块盘坏了数据还在。9.1 RAID 0条带化数据被切成块交替分布到多块磁盘上。读写可以并行进行速度成倍提升。但没有任何冗余——任何一块盘坏了所有数据全完。就像把一份文件撕成几页分给几个人保管一个人丢了就全没了。至少需要2块盘。适用场景追求极致速度数据丢了也无所谓。9.2 RAID 1镜像每块盘都有一个完整的镜像盘数据同时写到两块盘上。可靠性极高一块盘坏了还有另一块读性能可以提升可以从两块盘同时读。但可用容量只有50%——两块1TB的盘组RAID 1你只能用到1TB。适用场景数据安全要求极高。9.3 RAID 2位级条带 海明码数据按位分散到多盘额外用海明码做校验。需要很多盘数据盘校验盘实际中很少使用了解即可。9.4 RAID 3字节级条带 专用校验盘数据按字节分散到多盘有一块专门的盘存放奇偶校验信息。每次读写都涉及所有盘适合大文件顺序读写。但校验盘可能成为瓶颈。9.5 RAID 4块级条带 专用校验盘和RAID 3类似但以块为单位分散。校验盘成为写入瓶颈——每次写操作都要更新校验盘而校验盘只有一块。9.6 RAID 5分布式奇偶校验和RAID 4类似但校验信息分散存储在所有盘上而不是集中在一块盘上。解决了RAID 4的校验盘瓶颈问题。允许一块盘故障而不丢数据。至少需要3块盘。RAID 5是最常用的RAID级别兼顾了性能、可靠性和成本。适合文件服务器、NAS等场景。9.7 RAID 6双重奇偶校验使用两套校验信息允许两块盘同时故障。可靠性更高但写入性能更低每次写都要计算和更新两套校验。至少需要4块盘。适合对可靠性要求极高的企业存储。9.8 RAID 1010先做镜像RAID 1再做条带化RAID 0。高性能 高可靠但成本也最高——至少需要4块盘可用容量只有50%。适用场景高性能数据库服务器、核心业务系统。9.9 RAID 0101先做条带化RAID 0再做镜像RAID 1。看起来和RAID 10差不多但可靠性不如RAID 10——条带组中任何一块盘坏整个条带组都不可用只剩镜像组在撑。9.10 RAID选择建议RAID级别最少盘数可用容量容错能力读性能写性能适用场景RAID 02100%无极高极高追求速度数据不重要RAID 1250%1块盘高一般数据安全要求高RAID 53(n-1)/n1块盘高中等通用存储/NASRAID 64(n-2)/n2块盘高较低企业存储RAID 10450%1块/组极高高高性能数据库RAID 01450%1组极高高不推荐总结磁盘存储器管理的核心矛盾就一句话CPU太快了磁盘太慢了。为了解决这个矛盾操作系统想出了一整套方案调度算法让磁头尽量少跑、跑短路——FCFS公平但慢SSTF快但可能饿死人SCAN像电梯一样均衡C-SCAN更均匀LOOK系列是它们的优化版。分配方式决定文件在磁盘上怎么摆——连续分配简单快速但有碎片链接分配无碎片但随机访问差索引分配综合最优。空间管理追踪磁盘上的空地——空闲表法简单直观位示图法空间最省成组链接法效率最高。格式化让新硬盘从白板变可用——低级格式化划磁道扇区分区切蛋糕高级格式化建文件系统。缓存用内存帮磁盘打辅助——Page Cache让热数据不用每次都读磁盘。各种加速手段进一步压榨性能——提前读、延迟写、优化块分布、NCQ、I/O调度器……RAID让多块盘组队——条带化提速镜像保安全RAID 5是性价比之王。一句话总结磁盘存储器管理的全部目标就是让最慢的家伙尽可能不拖慢整个系统。