数据存储原理与安全防护:从RAID、加密到备份销毁实战

发布时间:2026/10/29 2:59:19
数据存储原理与安全防护:从RAID、加密到备份销毁实战

硬盘指示灯由绿转红的那一瞬间,很多人的心跳会跟着漏一拍。做基础设施这些年,我最怕的不是业务代码出 bug,而是凌晨接到电话说"那台存着三年数据的机器起不来了"。数据存储这四个字,平时没人愿意多看一眼,它不像前端框架那样天天有新版本,也不像算法模型那样能拿出来讲,可它偏偏是所有系统的地基。这篇文章想聊的不是某家厂商的产品说明书,而是把数据存储从底层介质、文件系统、冗余机制,一路讲到加密、备份、销毁这条完整链路上,我自己理解并且实际验证过的东西。

零基础的朋友也能看下去,因为我会把每个概念都落到"它到底解决了什么问题"上;有经验的同行也能翻到一些参数计算和实操命令,改改就能用。数据存储原理和数据安全防护这两件事本来就是一体两面——你不清楚数据在物理上是怎么落盘的,所谓的"加密""备份"就只能照抄配置文件,真出事的时候连从哪个方向查起都不知道。我见过太多人把 RAID 当成备份,也见过有人把文件拖进回收站再清空就以为数据没了,这些认知偏差迟早要用一次事故来买单。

下面这些内容,适合刚入行的运维、后端开发、想自己搭家用存储的爱好者,也适合需要给团队做存储方案评审的技术负责人。我会尽量用生活里的类比把原理讲透,再把命令和参数摆出来,最后把踩过的坑摊开说。

1. 数据存储这件事,先想清楚"存什么、怎么存、坏了怎么办"

1.1 三层抽象:从一块闪存颗粒到你双击打开的文件

很多人对存储的理解停留在"文件夹"这个层面,其实在操作系统眼里,数据要经过三层抽象才变成你能看见的东西。最底下是物理介质,机械盘里是盘片和磁头,固态盘里是 NAND 闪存颗粒;往上一层是块设备,操作系统把它看成一块由固定大小扇区(传统 512 字节,现在主流 4KB)拼起来的连续地址空间,它不关心里面装的是照片还是数据库文件;再往上是文件系统,它负责给这些块编号、建立索引、维护目录树,让"块"变成"文件"。

我习惯用仓库来类比:物理介质是仓库的水泥地和货架,块设备是给每个货位编了号的地面,文件系统则是那本记录了"3 号货架第 2 层放的是谁的货、什么时候放的、有多重"的台账。你在电脑上双击一个文件,操作系统干的事情是查台账拿到货位号,再去对应位置把东西搬出来。这个类比能解释很多现象:台账丢了(文件系统损坏),货其实还在货架上,所以数据恢复才有可能;货位编号错了(分区表损坏),整片区域就"找不到"了。

理解这三层非常关键,因为不同的安全防护手段作用在不同层上。全盘加密作用在块设备层,文件权限作用在文件系统层,应用层的字段加密则在你自己的代码里。搞混了层次,就会出现"我加密了怎么还能被读到"这种问题——因为你在应用层加密,却在文件系统层做权限,两套东西根本不搭界。

1.2 选型的第一性原则:先看写入模式和访问模式,再看容量

我见过太多方案讨论会,一上来就争论用机械盘还是固态盘、用 RAID5 还是 RAID10,争了两个小时没结论。原因很简单,大家跳过了最前面的问题:这批数据是怎么被写的,又是怎么被读的。

写入模式分顺序写和随机写。日志归档、视频监控、备份落地,基本都是大块顺序写,机械盘在这种场景下能跑出接近标称的带宽,性价比极高。数据库的 redo log、虚拟机的磁盘镜像、容器镜像层,则是典型的随机小 IO,机械盘在这种场景下会被寻道时间拖死,必须上固态。访问模式同理,冷数据一年读不了几次,热数据每秒要读上万次,两者的存储方案不该一样。

这里有个很实用的判断方法:把业务的 IO 特征画成一张表,横轴是块大小(4K、16K、128K、1M),纵轴是读写比例,然后对照介质的特性去匹配。固态盘在 4K 随机读上能到几十万 IOPS,机械盘只有一两百;但到了 1M 顺序写,一块企业级机械盘能稳定跑 200MB/s 以上,单位容量成本只有固态的十分之一左右。冷热分层不是玄学,是算账算出来的。

提示:不要用"平均"来评估存储需求。业务方说的"我们每天写 100GB"往往是均值,真正决定方案的是峰值和突发。峰值 IOPS 差一个数量级,方案就要推翻重来。

1.3 安全防护不是给文件夹加个密码,而是围绕数据生命周期布防

很多人对"数据安全"的理解就是加密压缩包加个密码,这顶多算一个环节。真正的防护要覆盖数据的整个生命周期:产生、传输、落盘、使用、归档、销毁。每个阶段的风险点完全不同,对应的手段也不一样。

产生阶段的风险是采集端被篡改,比如客户端上报的数据本身是假的,这时候要做的是来源校验和签名;传输阶段是链路窃听,靠 TLS 或者专线解决;落盘阶段是介质丢失或被物理接触,靠加密解决;使用阶段是越权访问和内部人员误操作,靠权限模型和审计日志解决;归档阶段是长期可用性和介质老化,靠校验和、定期迁移解决;销毁阶段最容易被忽视,删了文件不等于数据没了,后面我会专门讲。

这张生命周期图的价值在于,它能帮你发现方案里的空洞。我评审过不少方案,加密做得很好,备份也做了,但从头到尾没人提过"数据怎么销毁",等到设备报废要送修的时候才慌了神,硬盘拆下来堆在仓库里三年不敢处理。这种漏洞不是技术能力问题,是从来没往那个方向想过。

2. 存储原理拆解:数据到底是怎么被"放进去"和"取出来"的

2.1 机械盘和固态盘:两种完全不同的物理现实

机械硬盘(HDD)的原理说白了就是一张高速旋转的磁盘加一个悬浮的磁头。要读某个位置的数据,磁头得先移动到对应的磁道,这叫寻道时间,典型值几毫秒;然后等盘片转到正确的位置,这叫旋转延迟,7200 转的盘平均 4 毫秒左右。两个加起来,一次随机访问就是接近 10 毫秒。10 毫秒听起来很短,但换算成 IOPS 就是每秒 100 次左右,这就是机械盘随机性能的天花板。

固态硬盘(SSD)没有机械结构,它是靠浮栅晶体管存储电荷来表示 0 和 1。读取时直接给对应地址加电压,微秒级就能拿到数据。但 SSD 有个绕不开的限制:它只能按页写(通常 4KB 或 16KB),却必须按块擦(通常几百 KB 到几 MB)。这意味着你要改一个 4KB 的页,得先把整个块读到内存,改完再擦掉整块写回去,这叫写放大。主控里的 FTL(闪存转换层)负责把逻辑地址映射到物理地址,做磨损均衡,让每个块的擦写次数尽量平均。

这个物理差异带来一个非常实际的结论:SSD 的剩余空间越少,写放大越严重,性能和寿命衰减越快。所以生产环境里 SSD 一般只用到 70% 到 80% 的容量,剩下的留给主控做垃圾回收和磨损均衡。同理,删除文件后操作系统发出 TRIM 指令告诉 SSD"这些块不要了",主控才能真正回收,否则它还以为那里有有效数据,白白搬运。

对比维度机械硬盘 HDD固态硬盘 SSD
随机 4K 读 IOPS100 到 200数万到数十万
顺序带宽150 到 280 MB/s(企业级)500 MB/s 到数 GB/s
单位容量成本低高(约为 HDD 的 5 到 10 倍)
随机写特性受寻道限制受写放大和 GC 影响
断电数据保持长期稳定长期不通电有电荷流失风险
寿命指标机械磨损,通常 3 到 5 年以上按 TBW/DWPD 计算
适合场景冷数据、大文件归档、顺序写数据库、虚拟机、高并发小 IO

2.2 文件系统:把一堆扇区变成目录树的那本账

文件系统干的事情可以拆成三块:空间管理、命名与索引、一致性保证。以 ext4 为例,整个分区被切成若干块组,每个块组里有一个位图记录哪些块被占用了,还有一张 inode 表。inode 是文件的"身份证",里面存着文件大小、权限、时间戳、以及数据块在磁盘上的位置列表,唯独不存文件名——文件名放在目录项里,目录项负责把"名字"映射到"inode 号"。

这个设计解释了一个常见疑问:为什么重命名一个几 GB 的文件是瞬间完成的?因为改名只是改了目录项里的映射关系,数据块一个都没动。反过来,跨分区移动同一个文件就很慢,因为要真的把数据复制过去。

inode 数量是在格式化时定死的,这是个很容易踩的坑。ext4 默认按每 16KB 空间分配一个 inode,一块 1TB 的盘大概能分到 6100 万个 inode。如果你的业务是存大量小文件,比如几十 KB 的图片、日志切片、邮件,很可能空间还剩一大半,inode 却先用完了,报错 "No space left on device",但df -h显示还有空间,df -i才能看到真相。这时候只能重新格式化,用-i 4096或者-T small参数把 inode 密度调高,代价是可用空间会少一点。

文件系统的另一半价值是崩溃一致性。ext4 有 journal 日志,xfs 也有自己的日志机制,它们在真正改数据之前先把"我要做什么"写进日志区,断电重启后重放日志,把做到一半的操作补完或者回滚。但这只保证元数据一致性,不保证你正在写的那个文件内容是完整的。要保证业务数据不丢,还得靠应用层fsync或者数据库自己的 WAL 机制。

文件系统特点适合场景需要注意
ext4成熟稳定,工具链完善通用服务器、系统盘inode 数量格式化时固定,小文件多要提前算
xfs大文件和高并发表现好,支持在线扩容大容量数据盘、媒体存储不支持缩容
btrfs支持快照、校验和、子卷需要快照和自愈的场景部分场景稳定性需评估
zfs端到端校验、快照、压缩、去重自建存储、NAS吃内存,对硬件有要求
ntfs/exfat跨平台兼容移动硬盘、U 盘权限模型弱,不适合服务端

2.3 冗余的三种主流做法:RAID、多副本、纠删码

单块盘一定会坏,这是概率问题不是质量问题。企业级硬盘的年故障率大概在 1% 到 2%,盘多了之后,一年坏几块是常态。所以存储方案必须回答一个问题:坏一块盘的时候,数据还在不在,服务还跑不跑。

RAID 是最经典的答案。RAID0 是把数据切片分散到多块盘上,性能翻倍但没有冗余,一块坏全盘完;RAID1 是镜像,两块盘存一样的东西,容量利用率 50%;RAID5 用一块盘的容量存校验信息,允许坏一块;RAID6 用两块盘的容量存双校验,允许坏两块;RAID10 是先镜像再条带,兼顾性能和可靠性,容量利用率也是 50%。

RAID 级别最少盘数可用容量容错能力随机写性能典型场景
RAID02N × 单盘无最高临时数据、缓存
RAID121 × 单盘坏一块中等系统盘、小容量高可靠
RAID53(N-1) × 单盘坏一块较低(写惩罚)读多写少的归档
RAID64(N-2) × 单盘坏两块低大容量冷数据
RAID104N/2 × 单盘每组可坏一块高数据库、虚拟机

这里有一笔账必须算清楚,我见过太多人栽在上面。假设你有 12 块 16TB 的盘:做 RAID6,可用容量是 10 × 16 = 160TB;做 RAID10,可用容量是 6 × 16 = 96TB。看起来 RAID6 划算得多,但你要考虑重建时间。一块 16TB 的盘,按 150MB/s 的重建速率算,需要 16 × 1024 × 1024 ÷ 150 ≈ 111,848 秒,也就是超过 31 个小时。在这 31 小时里,阵列处于降级状态,剩下的盘要承受全部读压力,如果这时候再坏一块,RAID5 就彻底完了,RAID6 还能撑一次但风险陡增。

所以我的经验是:单盘容量超过 8TB 之后,RAID5 基本不要考虑了,要么 RAID6,要么 RAID10,要么上纠删码。这个结论不是拍脑袋,是重建窗口和故障概率算出来的。

纠删码(Erasure Code)是另一条路,常见配置像 8+3、10+4。以 8+3 为例,数据切成 8 个分片,再算出 3 个校验分片,总共 11 份分散在不同节点或不同盘上,允许任意丢 3 份。空间开销是 3/8 = 37.5%,可用率 8/11 ≈ 72.7%,比三副本的 33% 高出一倍多。代价是重建时要读 8 份数据做运算,网络和 CPU 开销都大,所以纠删码适合大容量、冷数据、跨节点的分布式存储,不适合高并发小 IO 的热数据。

2.4 快照和日志:让"误删"和"断电"不至于变成灾难

快照这个东西,用过就回不去了。它的原理主要有两种:写时复制(COW)和写时重定向(ROW)。COW 是指创建快照后,原始数据块被标记为共享,任何人要修改这个块,先把老内容复制到快照区,再改原块。ROW 则相反,新写入的数据直接写到新位置,老位置留给快照。两者各有优劣,COW 读快照快、写原始数据慢,ROW 反过来。

快照最实用的场景不是"防黑客",而是防手滑。rm -rf敲错一个字符、批量脚本跑错了目录、升级前忘了备份,这些事故的频率远高于外部攻击。有了小时级快照,恢复一个目录只要几秒钟。

日志(Journal/WAL)解决的是另一个问题:断电的时候正在进行的操作怎么办。数据库的 redo log、文件系统的 journal,本质都是"先记账再干活"。记账写完并落盘(fsync),才认为这次操作提交成功;真正改数据可以慢慢来,断电后重放日志补上就行。理解了这一点,你就明白为什么数据库调优里fsync相关的参数那么关键——把它关掉性能确实飞起,但断电时丢的不只是最后一条事务,可能是整个一致性。

3. 数据存储安全防护:把风险一个个摁住

3.1 加密放哪一层:介质加密、卷加密、文件加密、应用加密怎么选

加密的位置决定了它能防住什么。我把它分成四层,从下往上说。

**介质自加密(SED)**是硬盘自己带的功能,盘被拆走离开原机器就解不开。优点是零性能损耗、对上层完全透明;缺点是密钥管理依赖盘本身,不同厂商实现差异大,而且一旦整机被搬走,加密就等于没加。

卷级加密是操作系统层面把整个分区或逻辑卷加密,Linux 上是 LUKS,Windows 上是 BitLocker。数据在写入块设备之前就被加密,文件系统、数据库、应用完全感知不到。这是防设备丢失最划算的方案,性能损耗在现代 CPU 的 AES-NI 指令集加持下通常只有个位数百分比。

文件级加密针对单个文件,比如 GPG 加密一个压缩包。灵活,但管理成本高,你得记住哪个文件加密了、密钥在哪、怎么轮换。

应用层加密是在代码里对敏感字段加密,比如身份证号、手机号。它防的是"数据库被拖走"和"有权限的人乱看",因为密钥在应用侧,DBA 拿到数据库文件也解不开。代价是查询和索引会变复杂,模糊搜索基本告别。

加密层次防住的风险性能损耗运维复杂度典型工具
介质自加密单盘丢失极低低(依赖厂商)企业级 SED 盘
卷级加密整机/整盘丢失、报废流出低(有 AES-NI)中LUKS、BitLocker
文件级加密单个文件泄露中高GPG、age
应用层加密数据库泄露、内部越权视实现而定高自研或 KMS

我自己的搭配习惯是:卷级加密打底,应用层加密保护真正的敏感字段。卷级解决"硬盘被偷"这种物理风险,应用层解决"有账号的人不该看"这种逻辑风险。两层叠加,成本可控,覆盖面也够。

3.2 访问控制:权限模型解决的是"谁能碰",审计解决的是"谁碰过"

Linux 的权限模型是"用户-组-其他"三档,配合读、写、执行三个位。这套东西简单够用,但遇到"同一个目录,A 组能读写,B 组只能读,C 用户单独要有写权限"这种需求就不够了,得上 ACL。setfacl -m u:alice:rwx /data/project这种命令能把权限精确到单个用户。

再往上还有强制访问控制,SELinux 或者 AppArmor,它们不看用户是谁,而是看进程的标签允不允许访问某个资源。这东西初学很劝退,但在多租户或者对外服务的场景下价值很大——即使 Web 服务被拿下,攻击者也没法用它去读数据库文件。

不过我想强调的是另一个层面:权限只能防误操作,防不住有权限的人。真正管用的是审计。谁在什么时候读写了哪个文件、删了什么、改了什么权限,这些日志要单独存放、单独授权、定期检查。很多数据泄露事件事后复盘,日志要么没开,要么和业务数据放在同一台机器上被一起清掉了。

注意:服务账号不要用 root 跑。给每个服务单独建账号,只授予它需要的目录权限,日志目录单独挂载并设置noexec,nosuid。这几条成本极低,但能挡住相当一部分横向移动。

3.3 备份:3-2-1 原则、不可变快照和必须做的恢复演练

备份这块最容易自我感动。很多人做了定时任务,日志显示每天成功,就认为万事大吉,直到真的需要恢复时才发现:备份文件是空的、增量链断了一环、恢复出来的数据库起不来。

3-2-1 原则是底线:至少 3 份数据,存在 2 种不同介质上,其中 1 份在异地。往上还有 3-2-1-1-0 的说法,多出来的两个 1 和 0 分别是"1 份离线或不可变"和"0 错误(做完校验)"。这个原则之所以经典,是因为它针对的是不同故障域:本机磁盘坏、存储设备整体故障、机房级事故,三层防护各自对应。

不可变备份是这几年被反复强调的概念,针对的是勒索软件。它的核心是备份写进去之后在保留期内无法被修改或删除,即使攻击者拿到了管理员账号也没用。实现方式有对象存储的 WORM 策略、专门的防篡改设备、或者干脆刻录光盘、写入只读介质。

恢复演练是最容易被跳过的一步,也是最该做的一步。我的做法是每季度随机抽一个备份集,在一台干净机器上完整恢复一次,记录耗时。这个耗时就是真实的 RTO(恢复时间目标),它往往比方案里写的大得多。有个数据可以作为参考:没有演练过的备份,首次恢复成功率大概只有一半左右,剩下的失败原因五花八门,从介质损坏到依赖缺失到脚本路径写死。

备份窗口和带宽也得算。假设你要在 4 小时的窗口内完成 500GB 的增量备份,链路是千兆,实际有效带宽按 800Mbps 算就是 100MB/s,500 × 1024 ÷ 100 = 5120 秒,约 1.4 小时。看起来够,但别忘了备份完还要做校验读,读一遍又要 1.4 小时,加起来接近 3 小时,余量已经很薄了。如果再考虑压缩比不确定、源端磁盘 IO 争抢,4 小时窗口根本不够。备份方案里最容易被低估的就是校验的成本。

3.4 删除与销毁:你以为删了,其实它还在那儿躺着

这是我最想强调的一节,因为误解最深。

在文件系统里删除一个文件,本质上只是把目录项删掉、把 inode 标记为可用、把数据块标记为空闲。数据本身一个字节都没动。只要这些块还没被新数据覆盖,用恢复工具就能捞出来,这也是数据恢复行业存在的基础。

机械盘的彻底清除相对简单,用随机数据或者全零覆盖写几遍就行。但 SSD 不行,因为有磨损均衡和预留空间,你写到逻辑地址上的数据,主控可能映射到了完全不同的物理块,那些"已删除"的物理块你根本触达不到。所以对 SSD 做软件覆盖写是不可靠的。

正确姿势是:如果盘还在自己手上并且要继续用,用厂商提供的安全擦除工具(Secure Erase / Sanitize),它会通过主控把所有块(包括预留区)一次性清掉。如果盘要报废、送修、转让,最稳妥的是物理销毁,机械盘拆开划伤盘片或者消磁,固态盘直接粉碎闪存颗粒。

还有一种巧妙的做法叫加密擦除(Crypto Erase):整盘加密的前提下,你不需要擦数据,只要把密钥销毁,剩下的密文就永远解不开了。这也是卷级加密除了防丢失之外的第二个价值——它把"销毁"这个难题变成了"删一串几百字节的密钥"。

销毁场景机械盘做法固态盘做法说明
继续内部使用多次覆盖写厂商 Secure EraseSSD 覆盖写不可靠
转让给他人覆盖写 + 校验Secure Erase + 验证建议保留销毁记录
报废/送修消磁或物理破坏物理粉碎消磁对闪存无效
加密卷销毁密钥销毁密钥前提是密钥没有备份残留

4. 从零搭一套带加密和备份的小型存储:完整实操

4.1 盘位规划与分区,先把账算明白

假设我们手上有四块 8TB 的盘,要搭一台既能存业务数据、又做了加密、还有本地备份的机器。先做规划:四块盘做 RAID10,可用容量 4 × 8 ÷ 2 = 16TB;在此基础上做 LUKS 加密;加密卷上建 xfs 文件系统;另外用一块独立的小固态盘做系统盘和备份暂存区。

为什么不选 RAID6?四块盘的 RAID6 可用容量是 2 × 8 = 16TB,和 RAID10 一样,但写惩罚更严重(每次写要算两次校验),随机写性能差很多,四块盘规模下没有优势。

分区用 parted,注意对齐到 1MiB 边界,这是为了避开 SSD 的擦除块和机械盘的传统 63 扇区对齐问题:

# 查看现有磁盘 lsblk -o NAME,SIZE,TYPE,MODEL,SERIAL # 对每块数据盘创建 GPT 分区表和一个占满全盘的分区 parted -s /dev/sdb mklabel gpt parted -s /dev/sdb mkpart primary 1MiB 100% # 标记为 Linux RAID 类型,便于识别 parted -s /dev/sdb set 1 raid on # 其余 sdc、sdd、sde 同理

lsblk里能看到的 SERIAL 建议记录下来,将来某块盘故障时,靠序列号去机房找盘比靠盘符靠谱得多——重启之后/dev/sdb可能变成/dev/sdc,序列号不会变。

4.2 组 RAID10 并建文件系统,参数要跟着业务走

# 创建 RAID10 阵列,四块盘 mdadm --create /dev/md0 \ --level=10 \ --raid-devices=4 \ --chunk=256K \ /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1 # 查看同步进度,初次创建需要一段时间 cat /proc/mdstat # 保存阵列配置,避免重启后阵列名变化 mdadm --detail --scan >> /etc/mdadm.conf

--chunk=256K这个参数值得说一下。chunk 是条带大小,也就是数据往每块盘上连续写多少。chunk 太小,一次大 IO 会被切得很碎,增加开销;chunk 太大,单块盘的并发度上不去。经验值是:大文件顺序读写用 512K 到 1M,数据库这类随机小 IO 用 64K 到 256K。这里选 256K 是个折中。

接着在阵列上做加密,再在加密设备上建文件系统:

# 创建 LUKS2 加密卷 # key-size 512 对应 XTS 模式下的两个 256 位密钥,不是 AES-512 cryptsetup luksFormat --type luks2 \ --cipher aes-xts-plain64 \ --key-size 512 \ --hash sha256 \ --pbkdf argon2id \ --pbkdf-memory 1048576 \ --pbkdf-parallel 4 \ /dev/md0 # 打开加密卷,映射为 /dev/mapper/data_crypt cryptsetup open /dev/md0 data_crypt # 建 xfs 文件系统,大文件场景更合适 mkfs.xfs -f -L data /dev/mapper/data_crypt # 挂载 mkdir -p /data mount /dev/mapper/data_crypt /data

这里有几个参数必须解释清楚。aes-xts-plain64是目前块设备加密的标准选择,XTS 模式专门为磁盘加密设计,能抵御选择明文攻击,而老的 CBC 模式在磁盘场景下有已知弱点。--key-size 512容易引起误解,AES 的最大密钥长度是 256 位,XTS 模式需要两个密钥(一个加密数据、一个加密 tweak),所以 512 表示"两个 256 位密钥",写成 256 反而是降级。

argon2id 是密码哈希函数,用来从你输入的密码派生出真正的加密密钥。它故意设计得又慢又吃内存,就是为了抵抗暴力破解。--pbkdf-memory 1048576表示用 1GB 内存,--pbkdf-parallel 4表示 4 线程并行。这两个值越大越安全,但每次开机的解锁时间也越长。1GB 内存、4 线程的配置,解锁大概需要 1 到 3 秒,属于可以接受的范围。如果是在资源紧张的设备上,可以适当调低,但别低于 256MB。

4.3 自动挂载与密钥管理,别把密码写进脚本

手动cryptsetup open每次开机都要输密码,服务器场景下不现实。常见做法是用一个密钥文件代替密码:

# 生成 4KB 随机密钥文件 dd if=/dev/urandom of=/root/luks-keyfile bs=4096 count=1 chmod 400 /root/luks-keyfile # 把密钥文件添加为 LUKS 的一个槽位(槽位 0 仍然是密码) cryptsetup luksAddKey /dev/md0 /root/luks-keyfile # 在 /etc/crypttab 中配置开机自动解锁 echo 'data_crypt /dev/md0 /root/luks-keyfile luks,discard' >> /etc/crypttab

discard选项会透传 TRIM 指令,对 SSD 有用,能延长寿命、保持性能;但如果担心 TRIM 泄露"哪些块是空的"这种元信息,可以去掉,或者改用cryptsetup --allow-discards。这是个典型的安全性和性能的取舍,内部环境我一般会开,多租户环境会关掉。

密钥文件放在系统盘上,意味着系统盘被拿走等于加密失效。所以真正认真的方案会把密钥放在独立的密钥管理服务里,开机时通过网络拉取,或者用 TPM 芯片绑定机器。家用场景下,把密钥文件放在一个单独的 U 盘里,开机插上、解锁后拔掉,成本最低效果也不错。

4.4 备份脚本:增量、校验、保留策略一个都不能少

备份我用 rsync 做增量同步,配合硬链接实现"看起来像全量、实际只存增量"的效果。核心思路是用--link-dest指向最近一次备份目录,没变化的文件直接建硬链接,不占额外空间。

#!/usr/bin/env bash set -euo pipefail SRC="/data" DEST="/backup/data" STAMP=$(date +%Y%m%d_%H%M%S) LATEST=$(ls -1d ${DEST}/snapshot_* 2>/dev/null | tail -n 1 || true) mkdir -p "${DEST}/snapshot_${STAMP}" # 增量备份,未变化文件用硬链接指向上一份 if [ -n "${LATEST}" ]; then rsync -aHAX --delete --numeric-ids \ --link-dest="${LATEST}" \ "${SRC}/" "${DEST}/snapshot_${STAMP}/" else rsync -aHAX --delete --numeric-ids \ "${SRC}/" "${DEST}/snapshot_${STAMP}/" fi # 生成本次备份的文件清单和校验和 cd "${DEST}/snapshot_${STAMP}" find . -type f -print0 | sort -z | xargs -0 sha256sum > ../manifest_${STAMP}.sha256 # 校验:重新计算并比对 sha256sum -c ../manifest_${STAMP}.sha256 --quiet # 只保留最近 7 份 ls -1dt ${DEST}/snapshot_* | tail -n +8 | xargs -r rm -rf

几个细节值得展开。-aHAX里的 H 是保留硬链接、A 是保留 ACL、X 是保留扩展属性,少了这些,恢复出来的权限和 SELinux 标签可能全乱,服务起不来。--numeric-ids保证 UID/GID 按数字同步,跨机器恢复时不会因为用户名对不上而错乱。--delete让备份和目标保持一致,但一定要确认路径拼对了,写错一个字符就是把源数据删掉。

校验那一步是我强烈建议加的。sha256sum -c会重新读一遍所有文件并比对,虽然多花时间,但它能发现静默损坏——磁盘没报错,数据却已经变了。对于几百 GB 的备份,这一步可能要跑十几分钟,值得。

4.5 监控和恢复演练,把"能用"变成"验证过能用"

监控至少要看三样东西:磁盘健康、阵列状态、备份是否按时完成。

# SMART 健康检查,重点关注 Reallocated_Sector_Ct 和 Pending_Sector smartctl -H -A /dev/sdb # 阵列状态,降级的阵列会显示 degraded mdadm --detail /dev/md0 | grep -E 'State|Failed' # 加密卷状态 cryptsetup status data_crypt # 备份最后修改时间,超过 26 小时就该告警 find /backup/data -maxdepth 1 -name 'snapshot_*' -mtime -1 | wc -l

smartctl里我最关注两个指标:重映射扇区计数和待映射扇区计数。前者是已经坏掉并被替换的扇区数,数值一旦开始增长,说明盘的寿命到了尾声,该准备换盘了;后者是读取出错但还没重映射的扇区,通常意味着正在恶化。这两个指标比"通过/失败"的整体健康状态灵敏得多,等整体状态报失败,往往已经来不及了。

恢复演练不用做得很隆重,但一定要真做。我的做法是每月挑一份最近的备份,在一台测试机上完整恢复到新目录,然后: 第一,比对文件数量和总大小; 第二,随机抽 100 个文件做 sha256 比对; 第三,如果是数据库备份,实际启动一次并跑几条查询; 第四,记录耗时,作为 RTO 的实际值。

这套流程跑下来大概半小时,但它能把"备份成功"和"能恢复"之间的鸿沟填上。

5. 常见问题与排查实录

5.1 盘"消失"了:从物理层一路查到应用层

现象:机器重启后/dev/sdb不见了,lsblk里看不到,或者能看到但阵列起不来。

排查顺序我固定为四步。第一步看物理,dmesg | grep -i -E 'ata|scsi|nvme|error',如果出现link down、hard resetting link、I/O error,基本是线缆、背板或者盘本身的问题,换线换槽位试。第二步看阵列,mdadm --examine /dev/sdb1能看到这块盘的超级块信息和阵列 UUID,确认它是不是被误加了别的阵列。第三步看盘符漂移,用lsblk -o NAME,SERIAL对照序列号,很多时候盘还在,只是从 sdb 变成了 sdd,配置文件写死盘符就会出问题,所以前面才强调用/dev/disk/by-id/或者 UUID。第四步看挂载,/etc/fstab里写了不存在的设备,系统会进紧急模式,这时候要看journalctl -xb。

有一种特殊情况值得单独提:盘在系统里能看到,smartctl也正常,但读写报错。这往往是盘的固件进入了异常状态,或者 RAID 卡缓存电池失效导致写策略降级。前者可以尝试断电重启(真的断电,不是软重启),后者要检查 RAID 卡日志。

5.2 性能突然掉底:八成不是盘坏了

现象:业务反馈存储变慢,监控显示 IO 延迟从 2ms 涨到 200ms。

我遇到过最多的原因,按频率排序:第一是快满了,文件系统使用率超过 85% 之后,xfs 的碎片化加剧,SSD 的垃圾回收压力剧增,性能会断崖式下跌。这个用df -h一眼就能看出来。第二是后台任务,RAID 在重建、备份正在跑、updatedb或者日志轮转触发了大量 IO,这些在iostat -x 1里能看到%util打满。第三是内存不足,页缓存被挤掉之后,原本命中缓存的读变成了真实磁盘读,延迟直接翻几十倍。第四才是盘真出问题,这时候iostat会看到某块盘的await明显高于其他盘,配合 SMART 能定位。

iostat -x 1里我重点看三个值:r_await/w_await(平均等待时间,正常应该在个位数毫秒)、aqu-sz(平均队列长度,持续大于 2 说明有排队)、%util(设备繁忙度,对机械盘接近 100% 就是瓶颈,对 SSD 参考意义弱一些)。用fio做基线测试也很有必要,新机器上线前跑一遍随机读写,把数字记下来,出问题时才有对比的基准。

# 4K 随机读基线测试,跑 60 秒 fio --name=randread --ioengine=libaio --direct=1 \ --bs=4k --rw=randread --size=4G --numjobs=4 \ --iodepth=32 --runtime=60 --time_based --group_reporting

5.3 备份恢复了却用不了:几个高频的坑

坑一:权限和属主全错。用cp或者不带-a的rsync备份,恢复出来所有文件都成了当前用户,服务启动报权限错误。解决办法是备份时加-aHAX --numeric-ids。

坑二:硬链接变成了独立文件。备份时没加-H,原本用硬链接节省空间的目录,恢复后体积暴涨,还可能把磁盘撑满。这个坑在备份大量重复内容的场景下特别致命。

坑三:增量链断了。用--link-dest做增量时,如果中间有一份快照被误删,后面基于它的硬链接还在,但再下一份就找不到基准了,恢复出来会缺文件。所以保留策略要么整链保留,要么每次做全量校验。

坑四:数据库备份不是一致状态。直接rsync正在运行的 MySQL 数据目录,拷出来大概率起不来,因为数据文件和 redo log 不在同一个时间点。数据库必须用mysqldump、xtrabackup这类工具做热备,或者先锁表再拷文件。

坑五:路径写死。备份脚本里写的是/data,恢复到测试机的/restore之后,配置文件里的路径全对不上。恢复流程里必须包含一步"改配置",这一步要提前写进文档,不能靠现场发挥。

5.4 常见问题速查表

现象最可能原因快速验证处理方向
No space left on device但df -h有空间inode 耗尽df -i清理小文件,重建时调高 inode 密度
阵列状态 degraded某块盘掉线或坏道mdadm --detail、smartctl换盘后mdadm --add重建
加密卷打不开密钥文件丢失或密码错cryptsetup luksDump用备用密钥槽位,检查 crypttab
写入延迟突增磁盘使用率过高或后台重建iostat -x 1、cat /proc/mdstat扩容、错峰、限制后台任务速率
备份文件大小正常但恢复失败增量链断裂或数据不一致抽样 sha256 比对改为全量+校验,重建备份链
删除文件后空间没释放进程仍持有文件句柄lsof +L1重启相关进程或truncate
SSD 写入性能下降剩余空间不足或未开 TRIMfstrim -v、df -h保留 20% 空闲,配置定期 trim

6. 几个只有踩过才知道的经验

做了这么多套存储方案,有几个认知是吃了亏才建立起来的,写出来给同行参考。

RAID 不是备份,快照也不是备份。RAID 防的是盘坏,快照防的是误删,两者都防不住"整个文件系统被加密勒索"或者"误执行了删除脚本并且快照也一起被删"。真正的备份必须在物理上或者逻辑上独立,写进去之后改不动。我现在的标准是:本地快照做小时级,异地备份做天级,其中一份离线保存,接受它带来的不便。

容量规划永远比你以为的要快用完。原因不是数据增长超预期,而是"临时文件"和"测试数据"没人清理。我的做法是给每个目录设配额,超过阈值自动告警,季度做一次盘点。这件事听起来很土,但确实有效,能把"某天突然发现盘满了"变成"提前一个月就知道要扩容"。

重建阵列的时候千万别做别的重活。我见过一次事故,RAID5 重建过程中有人跑了个大批量数据导入,剩下的盘 IO 被抢满,重建速率从 150MB/s 掉到 20MB/s,本来 10 小时能完成的重建拖了三天,第三天第二块盘也挂了,数据全没。这个教训很贵,从那之后我在所有阵列重建期间都会限制业务 IO,宁可慢一点。

加密的密码和密钥,要有"人没了怎么办"的预案。这不是开玩笑,一个同事离职带走了一台加密笔记本的密码,里面的数据花了很大力气才恢复。企业环境要用密钥托管或者多人分片保管,家用场景至少把恢复密钥打印出来锁在抽屉里。

别迷信"企业级"三个字。同一批次采购的硬盘,故障时间往往高度相关,因为它们来自同一条产线、同一批原料、经历了同样的运输。分批采购、混用不同批次,能显著降低"一起坏"的概率。这条经验在 SSD 上同样适用。

最后一条,也是最实在的:所有方案都要能在一张纸上画出来。画不出来的方案,出故障的时候没人能快速定位。我给自己定的规矩是,任何存储架构必须能用"数据从哪来、经过哪几层、落在哪块盘上、坏了怎么恢复"这四句话讲清楚。讲不清楚,说明自己也没想明白,那就先别上线。