你在编辑器里按下保存,界面几乎立刻就安静下来。可这并不等于数据已经稳稳落到了存储介质上。它可能还停在进程的缓冲区里,也可能刚进入内核的页缓存,甚至已经交给硬盘控制器,却仍躺在易失性的写缓存中。此时如果突然断电,“保存成功”与“下次开机还能读到”完全可能是两回事。
存储系统麻烦就麻烦在这里:上层希望它像一个又快、又大、又便宜、永不出错的柜子;底层却只能用容量、延迟、成本和可靠性各不相同的介质去拼。操作系统的工作不是消灭这些矛盾,而是在它们之间建立一套稳定的规则:把不同设备抽象成统一接口,安排请求的先后顺序,在故障出现时尽量发现问题,并把物理空间组织成应用能理解的文件和目录。
这一节我们不急着背接口名。先跟着一份数据走完旅程:它从内存出发,穿过文件系统和块层,落到 HDD 或 SSD;再反过来看看,当设备变慢、空间耗尽、某块介质损坏时,系统究竟能做什么,又有什么做不到。
同样是“磁盘”,机械硬盘和固态硬盘面对请求时,成本模型完全不同。机械硬盘最怕磁头来回跑,固态硬盘没有磁头,却怕小块随机写把内部页块整理得七零八落。理解这两个模型,后面的调度、缓存和 RAID 才不会变成孤立的名词。
想象一台老式唱片机。盘片在主轴上高速旋转,执行器带着磁头横向移动。盘片表面被组织成一圈圈磁道,每条磁道又包含许多扇区。读某段数据时,控制器至少要完成三件事:把磁头移到目标磁道,等待目标扇区转到磁头下方,再让数据通过接口传走。
一次访问的近似时间可以写成:
寻道需要机械运动,通常是其中最不稳定的一项。旋转等待取决于转速和当前位置;如果目标位置随机分布,平均要等半圈。以 7200 转/分钟为例,一整圈约为 ,平均旋转等待约为 。真正读数据的传输阶段可能很快,但前两项不会因为你只读 4 KiB 就自动消失。
这也解释了一个很有体感的现象:复制一个连续的大文件时,磁头沿着相邻位置读下去,前置成本可以摊到大量数据上;扫描几十万个散落的小文件时,每次只拿一点内容,却反复付出寻道和旋转等待,吞吐量会突然掉下去。顺序访问与随机访问的差距,不是文件系统故意刁难,而是机械结构直接写进了性能模型。

一次 HDD 访问由寻道、等待目标扇区旋转到磁头下方和数据传输三部分组成。
操作系统通常不会拿“第几个盘片、第几条磁道、第几个扇区”与上层交流。设备对外提供从 0 开始编号的逻辑块地址,也就是 LBA。文件系统只说“读这些逻辑块”,控制器负责把逻辑地址映射到实际位置。现代硬盘内部还会使用区域位记录、缺陷重映射等办法,上层看到的线性编号与真实几何结构并不是简单的一一对应。
CHS 很适合帮助我们理解盘片、磁头和扇区,但不能把现代硬盘当成一张可以靠 CHS 精确推算的几何表。现代系统主要使用 LBA,控制器还会隐藏坏扇区替换和内部布局细节。
SSD 用 NAND 闪存保存电荷状态,没有机械寻道和旋转等待,所以随机读取通常比 HDD 快得多。不过 NAND 的规则有点反直觉:数据按“页”读取和编程,却按更大的“块”擦除,而且已经写过的页不能像内存那样直接原地覆盖。
假设文件系统想更新逻辑块 42。SSD 控制器往往不会把旧物理页擦掉再原地写入,而是把新版本写到另一个空闲页,修改“逻辑块 42 现在对应哪个物理页”的映射,并把旧页标成无效。等空闲页越来越少,垃圾回收才挑选一个块,把其中仍有效的页搬走,擦除整个块,重新得到可写空间。
这套映射由闪存转换层 FTL 维护。它解决了两个直接矛盾:上层需要可覆盖的线性块设备,底层却只能页写、块擦;少数热点数据会被反复修改,闪存单元却有有限的擦写寿命。为此,控制器还会做磨损均衡,让擦写不要长期集中在同一批物理块上。

SSD 按页读写、按块擦除;更新时先写入新物理页,再安全更新 FTL 映射,避免原地覆盖。
代价也随之出现。主机只写入 4 KiB,不代表 NAND 只发生 4 KiB 的写入。有效页搬迁、元数据更新、垃圾回收都会产生额外写入。我们用写入放大系数描述这种差距:
持续小块随机写、盘内空闲空间紧张、垃圾回收频繁时, 往往会上升。SSD 可能出现阶段性的延迟尖峰,寿命消耗也会加快。TRIM 或 discard 的意义就在这里:文件系统删除文件后,把“不再需要这些逻辑块”告诉设备,控制器便能提前把相应页视为无效,不必在垃圾回收时继续搬运它们。
SSD 还可能用 DRAM 保存映射和缓存,用一部分 NAND 模拟速度更快的写入缓存。短时间测速很好看,长时间连续写满缓存后速度却下降,并不矛盾。你测到的是一整套控制策略的表现,不只是闪存单元本身的速度。
下面的实验把 HDD 一次随机访问拆成寻道、旋转和传输三部分。你可以改变转速、寻道时间、请求大小和顺序程度,观察为什么“提高接口带宽”不一定能拯救大量小随机 I/O。实验只是解释成本模型,不代表某一具体设备的承诺值。
如果每个文件系统都要分别理解 HDD 的磁道、SSD 的页和网络存储的协议,系统很快就会失控。块设备抽象把差异压到接口下面:上层看到一段可按编号访问的逻辑块空间,可以读、写、刷新或丢弃某些范围;设备驱动和控制器再把这些动作翻译成具体命令。
这个抽象故意隐藏了物理布局。它让同一个文件系统可以放在 SATA 硬盘、NVMe SSD、虚拟磁盘、加密映射或 RAID 阵列上,也让多个物理设备可以在上层表现成一个逻辑设备。不过,隐藏不等于成本消失。HDD 的寻道、SSD 的垃圾回收、网络的往返延迟仍会从完成时间中露出来。

统一块接口把上层文件请求转换为 LBA,再由 HDD 控制器或 SSD 的 FTL 处理底层物理映射。
假设程序第一次读取一个不在缓存里的文件片段,大致会经过下面这条路径:
程序发出读取请求。系统调用进入内核后,虚拟文件系统根据文件描述符找到具体文件系统,再把“文件中的偏移量”解释成需要访问的文件数据或元数据。
文件系统先检查页缓存。如果目标页已经在内存里,读取可以直接从缓存完成;若不在,文件系统才根据自己的块映射找到设备上的逻辑块。
块层把一个或多个范围组织成 I/O 请求。相邻请求可能被合并,请求也可能进入调度器或直接分发到硬件队列。多核系统会尽量避免所有 CPU 都争抢同一把队列锁。
驱动把请求转换成设备能理解的命令,控制器完成 DMA 传输。设备完成后通过中断或轮询通知内核,等待的任务被唤醒,数据最终交回进程。
读路径里最容易被忽略的是页缓存。第二次读取同一文件往往很快,测到的可能是内存,而不是设备。文件系统还会根据访问模式做预读:既然程序正在顺序读取第 10、11、12 页,系统可以猜测第 13 页很快会被用到,于是提前发起 I/O。猜对了能隐藏延迟;猜错了会浪费带宽和缓存空间。
普通写调用返回时,数据通常已经复制进内核管理的缓存,但未必持久化。内核可以稍后批量回写,把相邻小写合并成更高效的大写。这提高了吞吐量,也让应用不用每次都等待设备。
当数据库或日志系统真的需要“现在断电也不能丢”时,就要使用同步语义,并把数据与必要的元数据按正确顺序提交。文件系统会用日志、写时复制、屏障、刷新缓存或强制单元访问等机制维持顺序。这里的关键不是调用一个名字听起来很安全的函数,而是建立完整的持久化协议:先写什么,什么时候要求落盘,崩溃后以什么记录判断操作是否完成。
“写调用成功”“文件系统已提交”“设备缓存已刷新到非易失介质”是三个不同阶段。应用如果需要崩溃一致性,必须明确使用文件系统提供的同步语义;只看界面提示或关闭文件句柄并不足以推出数据已经持久化。
设备一次能接收多少未完成命令,决定了操作系统可以暴露多少并行性。对机械盘来说,适量排队能给控制器留下重排空间;队列太深则会让某个交互请求排在大量后台请求后面。对 NVMe SSD 来说,多队列和并行通道能显著提高吞吐量,可队列填得过满仍会增加尾延迟。
所以“队列越深越快”只说对一半。吞吐量可能上升,但单个请求从进入队列到完成的时间也可能变长。操作系统需要背压:当下层拥堵时,限制继续涌入的请求,避免缓存无限膨胀,也避免少数任务把共享设备占满。
浏览器在读缓存,编译器在写目标文件,备份程序正顺序扫描整个目录。三个任务同时把请求送到一块 HDD,如果严格按到达顺序执行,磁头可能在盘片内外圈之间反复横跳。调度器要做的事情看似只是换个顺序,实际却在三个目标之间取舍:减少设备成本、缩短等待时间、避免某类请求长期得不到服务。
先来先服务 FCFS 最容易解释:谁先到就先做。它保留到达顺序,也不会因为位置不巧而主动饿死某个请求,但完全不关心机械移动成本。
最短寻道优先 SSTF 每次选择离当前磁头最近的请求,平均移动距离往往更小。问题是,磁头附近持续有新请求到来时,远处请求可能一再被插队。这就是吞吐量改善与饥饿风险之间的交换。
SCAN 像电梯一样沿一个方向移动,途中处理遇到的请求,到达边界后再反向。它减少无规律往返,也给等待时间提供了较稳定的上界。LOOK 与 SCAN 的思路相近,但方向上已经没有请求时就回头,不必真的走到物理边界。
C-SCAN 只在一个方向提供服务,到达一端后回到另一端重新开始。这样不同位置看到的等待分布更均匀,但返回动作仍有成本。C-LOOK 同样会在最远请求处折返,而不是走到设备端点。

同一组磁道请求采用不同调度策略时,磁头移动距离、公平性与等待时间会产生不同取舍。
输入请求磁道、初始位置和移动方向,再切换算法。轨迹图会把每一步的移动画出来。这里计算的是教学用的“磁道距离”,没有模拟旋转位置、设备缓存和控制器内部重排。
这些算法很适合建立直觉,却不能直接代表现代操作系统的全部实现。首先,SSD 没有磁头,按逻辑块距离排序不再等价于减少寻道。其次,NVMe 设备有多个提交队列,控制器内部也会并行处理和重排命令。操作系统看见的完成顺序未必就是介质内部执行顺序。
现代 Linux 块层使用多队列机制,把软件队列与硬件派发队列分开。设备可以选择不附加额外调度策略,也可以使用面向延迟或公平性的策略。例如,deadline 思路会给请求设置期限,同时适度按扇区位置批处理,防止某些请求无限等待;BFQ 更强调按任务或控制组分配带宽,并为交互负载争取较低延迟。更复杂的策略能提供更好的服务目标,也会带来额外的 CPU 和管理开销。
选择调度策略时,先问清楚瓶颈是什么。单块机械盘经常受寻道限制;高并发 SSD 更关心队列并行与软件开销;桌面环境在意交互延迟;共享服务器还要防止一个租户吞掉全部带宽。没有一个名字可以脱离设备和工作负载永远获胜。
存储错误并不总是“整个盘突然死掉”。一根链路上的电气噪声可能翻转几个比特,闪存单元的电荷状态可能越来越难判定,磁盘表面也可能出现无法稳定读取的扇区。更棘手的是静默损坏:设备返回了数据,但内容已经不对,而上层没有立刻察觉。
奇偶校验给一组比特补一个校验位,可以发现某些错误,但信息量太少,通常无法指出到底哪里错了。校验和把一段数据压缩成较短的值,读取时重新计算并比较;设计不同,能发现的错误模式也不同。CRC 特别适合发现传输中常见的突发错误,但“检出概率很高”不等于“可以恢复原文”。
纠错码会保存更多冗余信息,使读取端在错误数量不超过能力范围时定位并修正错误。现代 HDD 和 SSD 都会在设备内部使用纠错机制,SSD 控制器还会根据闪存状态调整读取和纠错策略。纠错需要额外空间、计算和延迟;介质老化后,需要纠正的错误增多,最终仍可能越过可恢复边界。

奇偶校验和 CRC 主要负责发现错误,ECC 利用冗余信息定位并纠正一定范围内的位错误。
可以把可靠性保护看成一层层的接力:链路层检查命令和传输,设备内部保护物理页或扇区,文件系统可以为数据或元数据保存校验,阵列用镜像或校验块承受设备故障,应用再用日志和副本处理更高层的一致性。每层知道的上下文不同,不能指望最底层替上层解决所有问题。
设备出厂时就可能存在不可用单元,运行中也可能出现新缺陷。控制器会维护备用空间,把有问题的物理位置替换掉,同时保持原来的 LBA 不变。这让上层不必跟着物理缺陷改地址,却也意味着用户看不到每一次内部搬迁。
健康统计能暴露温度、重映射、介质错误、累计写入等线索,但它更像仪表盘,不是预言机。某些设备在故障前会持续告警,也有设备几乎没有明显预兆就失效。发现指标恶化时应尽快迁移和替换;指标正常时仍然需要备份。
即便每个扇区最后都能正确读取,断电仍可能让多步更新停在中间。例如,文件系统先把目录项指向新数据块,数据块本身却还没写完;重启后,目录结构看似存在,文件内容却无效。日志型文件系统会先记录足以恢复的操作意图或元数据,再按协议提交;写时复制文件系统则把新版本写到新位置,最后原子地切换根引用。
两者都不是“永远不丢数据”的魔法。日志范围可能只覆盖元数据,缓存刷新可能被设备错误实现,存储栈中的某层也可能没有正确传递持久化语义。可靠系统必须同时考虑写入顺序、原子性、校验、冗余和恢复流程。
新硬盘接上电脑后,应用不能直接在一串 LBA 上创建“课程/笔记.md”。中间还需要划定空间边界、选择组织方式、创建文件系统,并把它接到系统的目录树中。每一层都在回答不同问题,混在一起就很容易误操作。
分区表描述一块设备被切成哪些连续区域。GPT 是现代系统常见的分区方案,它在设备上保存分区的起止位置、类型标识和唯一标识等信息。修改分区边界改变的是空间地图,不会自动把内部文件系统安全地放大或缩小。
逻辑卷管理再加一层映射。它可以把多个物理区域汇成存储池,切出逻辑卷,也能在合适条件下扩容、建立快照或迁移数据。灵活性来自额外元数据和映射关系,因此恢复时也要保住这一层的信息。
文件系统才负责把块组织成文件、目录和元数据。创建文件系统时会写入它自己的核心结构,例如超级块、空闲空间信息和根目录。所谓“格式化”在日常语境中通常指这一步,而不是在厂外重新制作 HDD 的物理扇区或 SSD 的 NAND 结构。

物理磁盘经分区和卷管理创建文件系统,再挂载到目录树,用户最终通过统一路径访问文件。
最后是挂载。类 Unix 系统没有给每个卷永久分配一个独立字母,而是把某个文件系统的根接到现有目录树中的挂载点。挂载之后,进程通过路径进入它;卸载则要先确保没有仍在使用的文件,并把待写数据妥善提交。
一条常见路径可能是:物理 SSD 上的分区,先进入加密映射,再加入逻辑卷,逻辑卷上创建文件系统,最后挂载到某个目录。RAID 也可以出现在这条链里。上层只看见下一层提供的逻辑块设备,因此组合很灵活。
灵活也会增加排障难度。空间不足时,要辨认究竟是文件系统没有扩容、逻辑卷没有获得新范围,还是底层存储池已经耗尽。性能异常时,也要沿栈检查缓存、加密、阵列、队列和物理设备,不能只盯着最上面的文件路径。
开机后,固件先找到可启动目标,再加载引导程序;引导程序找到内核和初始内存文件系统;内核初始化驱动、识别根设备,最后挂载真正的根文件系统。不同固件和系统的具体布局不同,但共同点是:系统必须在完整用户空间尚未启动前,就掌握足够信息去找到下一阶段。
这也是为什么误删一个体积很小的引导分区,可能让其余数百 GiB 数据都“看起来消失”。数据卷本身未必坏了,只是启动链断在前面。修复时应先分清引导问题、卷映射问题和文件系统损坏,避免把“不能启动”直接等同于“必须重装并格式化”。
你开了很多应用,物理内存逐渐吃紧,系统通常不会立刻把某个进程赶走。它会回收可以重建的缓存页,也可能把暂时不用的匿名页移到交换空间,把有限的物理内存留给当前活跃的数据。
交换空间可以放在专用分区,也可以放在文件中。对内存管理器来说,它提供的是存放匿名页后备内容的位置。文件页通常已有对应文件,干净页可以直接丢弃,需要时再从文件读取;匿名页没有天然文件后备,要回收就需要交换空间或其他保存手段。

交换空间扩展可用容量,但访问速度远慢于主存;频繁缺页会让 CPU 大量等待 I/O 并形成抖动。
从交换空间换入页面,需要经历缺页处理和存储 I/O。即使使用 SSD,延迟也远高于直接访问 DRAM;如果许多工作集都超过物理内存,系统可能不断把页面换出又立刻换入,形成抖动。此时 CPU 并没有在做有用计算,大量时间花在搬运页面上。
所以交换空间的价值是提供缓冲和生存余地,而不是把 8 GiB 机器无损变成 16 GiB。它能容纳一部分长期不活跃页面,让活跃页面获得更多内存,也能让系统在短时内存尖峰中争取处理机会。工作集长期超量时,根本办法仍是减少负载、限制进程、优化内存使用或增加物理内存。
需要腾出物理页时,内存管理器还要回答“谁先离开”。最简单的 FIFO 按进入内存的先后选择页面,记录成本低,却可能赶走正在频繁使用的老页面,甚至出现增加页框后缺页反而更多的异常现象。理想的 LRU 选择最长时间没有访问的页面,更贴近局部性规律,但每次访问都维护全局精确顺序会很贵。
时钟或第二次机会算法提供了一个实用折中:页面排成环,扫描指针遇到近期访问过的页就清除访问标记并暂时放过,遇到没有近期使用证据的页再回收。真实操作系统会进一步区分匿名页与文件页、活跃与不活跃集合,也会结合脏页回写成本和内存控制组限制。它们追求的是成本可控的近似判断,而不是教科书意义上的完美 LRU。
这里还有一个容易忽略的取舍。回收干净文件页不需要先写交换区,但以后访问还要从文件重新读取;换出匿名页能释放内存,却会产生写 I/O。系统必须同时估计“这个页多久后还会用”和“把它移走有多贵”,因此同一个交换参数放在不同负载上可能得到相反效果。
zram 在内存中提供压缩块设备,常被直接用作交换设备。它用 CPU 做压缩,换取在同样物理内存中容纳更多页,而且不需要落到慢速设备。它仍占用 RAM,只是压缩后占得更少。
zswap 则是交换路径前面的压缩缓存。页面准备换出时先尝试压缩并留在内存池,池满或页面被淘汰后,仍可能写入后端交换设备。它用 CPU 和一部分内存换取更少的交换 I/O。两者都可能改善特定负载,也都不是免费容量:不可压缩的数据收益较小,压缩与解压还会占用 CPU。
观察交换问题时,不要只看“用了多少交换空间”。更有意义的是换入换出是否持续发生、缺页延迟是否升高、活跃工作集是否超过内存,以及系统是否已经在抖动。长期放在交换区的冷页不一定正在拖慢机器。
一块存储可以焊在主板附近,也可以隔着机房网络,甚至由远端服务把对象分布到多台机器上。距离越远,协议越要处理寻址、排队、重试、权限和故障;上层得到的语义也会变化。
SATA 延续了面向磁盘设备的命令与控制模型,常见系统通过 AHCI 使用它。它足够成熟,适合 HDD 和许多 SSD,但软件栈与队列结构形成于并行度较低的设备时代。
NVMe 从一开始就面向非易失性存储和 PCIe,使用提交队列与完成队列,让不同 CPU 或任务可以并行投递大量命令,减少共享锁与传统协议转换。NVMe 描述的是主机与非易失存储通信的协议族;M.2 是外形与连接器规格,PCIe 是总线。三者经常一起出现,却不是同义词。M.2 插槽上的设备也可能走 SATA,NVMe 也能出现在其他形态中。

SATA 强调成熟兼容,NVMe 通过 PCIe 提供低延迟多队列并发,网络存储则以网络往返换取共享和扩展能力。
接口带宽只是上限的一部分。真实延迟还包括文件系统、队列等待、控制器、介质和数据复制。随机小 I/O 经常受单次完成延迟限制,顺序大 I/O 才更容易把链路带宽跑满。看到“最高几 GB/s”时,先确认队列深度、请求大小、读写比例和持续时间。
NAS 通常通过网络提供文件级访问。客户端看到目录、文件名和权限,服务端文件系统负责把这些操作映射到自己的存储。它适合共享文件,但性能和一致性会受网络及文件协议语义影响。
SAN 更偏向通过专用或通用网络提供块级存储。主机拿到一个逻辑块设备,通常由主机自己创建文件系统。多个主机若同时写同一个普通文件系统,必须有额外的集群协调;“大家都能连上同一个块设备”不等于“大家能安全地随便写”。
对象存储以对象键和接口操作数据,不承诺天然呈现为本地可随机改写的块设备或传统 POSIX 文件系统。它擅长大规模、扁平命名和服务端冗余,但更新一个对象、列目录、原子重命名等语义可能与本地文件系统不同。把云端对象桶挂成目录很方便,不能因此假设所有本地文件操作都同样便宜、同样一致。
假设一台服务器只有一块盘,盘坏了服务就停。最直接的想法是再放一份副本;如果还想提高吞吐量,可以把连续数据条带化到多块盘;如果不愿为完整副本付出一倍容量,也可以保存校验信息,在单盘故障后通过其余数据重建。
RAID 就是在这些想法之间选择组合。它把多块成员设备组织成一个逻辑设备,目标可能是性能、容量、故障容忍,或三者的折中。RAID 并不自动等于“更安全”,因为不同级别的冗余能力差别很大,控制器、元数据和重建过程本身也会引入风险。

不同 RAID 级别通过条带化、镜像和分布式校验,在速度、可用容量与容错能力之间做出不同取舍。
RAID 0 只做条带化。数据分散到多块盘,并行访问可以提高吞吐量,可任意一块成员损坏都会让阵列缺失一部分数据。它没有冗余,名字里有 RAID 也不能拿来容错。
RAID 1 保存镜像。两块同容量盘组成常见镜像时,可用容量约等于一块盘;读取可以从不同副本分担,写入要让副本保持一致。它能承受一定的成员故障,但误删除、勒索加密和应用写错会被同步复制到所有镜像。
RAID 5 用分布式校验承受一块成员盘故障,可用容量约为 ,其中 是盘数, 是最小成员容量。小写入可能要读取旧数据和旧校验、计算新校验,再写回数据与校验,形成额外开销。掉电发生在条带更新中间时,还要面对数据与校验不一致的写洞问题。
RAID 6 保存两套独立校验,可承受两块成员盘故障,可用容量约为 。它用更多容量与计算换来更大的故障余量,写入代价通常也高于单校验方案。
RAID 10 先建立镜像组,再在镜像组之间条带化。常见配置的可用容量约为总原始容量的一半,读写性能与恢复行为通常比大规模单校验阵列更直接。它能承受多少块盘同时坏,取决于坏盘是否落在同一个镜像组;“一定能坏两块”这种说法并不严谨。
选择 RAID 级别和成员数量,再点击盘位模拟故障。实验按常见、等容量成员的简化模型计算,重点是理解容量与故障域,不替代实际阵列设计工具。
成员盘失效后,阵列通常进入降级状态。替换盘加入后,系统要读取其余成员,重新计算并写出缺失内容。这个过程会占用大量带宽,正常业务与重建互相争抢 I/O;阵列越大、成员越慢、业务越忙,风险窗口可能越长。
重建还会把其余盘完整读一遍,原本不常访问的潜在错误可能在此时暴露。设置热备盘能缩短“等待人工插盘”的时间,却不能缩短所有重建过程,也不能阻止误删、软件错误、火灾或整机丢失。
RAID 解决的是一部分设备故障下的持续服务问题,备份解决的是回到过去版本、跨故障域恢复的问题。需要保留独立副本,并定期验证它真的能恢复。镜像、快照、同步和备份各有作用,不能只凭“有两份”就把它们当成同一件事。
现在回到开头那次保存。应用先把修改交给内核,文件系统决定数据和元数据如何落位,块层负责合并、排队和分发,驱动把命令送到控制器。HDD 要移动磁头,SSD 要维护逻辑页与物理页的映射;设备可能暂存写入,也可能立刻提交到非易失介质。阵列在多个成员之间做条带、镜像或校验,远程存储还要再经过网络。
这条链里没有一个单独指标能说明全部体验。带宽高不代表小 I/O 延迟低,平均延迟低不代表尾延迟稳定,设备健康不代表文件系统一致,RAID 正常不代表有可恢复的历史副本。排查时最好按三个问题往下走:请求卡在哪一层,当前层在等待什么,优化它会牺牲什么。
面对一个存储方案,也可以按同样思路反过来设计:
存储设计的难点并不是找到“最快的盘”,而是让每一层的承诺能接得上:上层不要假设下层从未保证的语义,下层也要把完成、错误和持久化状态如实传回。这样一次简单的“保存”,才有可能在性能和可靠性之间得到可解释的结果。