操作系统内功 · 第 48 篇|XFS 与 Btrfs:ext4 之外的现代文件系统

ext4 之后的两种世界观

第 23 篇讲过 ext4 的日志机制:日志仲裁元数据写入,就地覆写保证崩溃一致性,是二十年来最常见的稳妥默认。但当需求越出「一个可靠的大盘」这个范畴,ext4 的舒适区之外还有两个方向值得深入。一是规模:几十 TB 的阵列、成百上千并发写大文件的负载,元数据操作的串行化会成为瓶颈,这是 XFS 的主场。二是功能:快照要瞬间完成、数据要逐块校验、坏块要能自愈、备份要增量发送,这些把卷管理器与备份软件的活儿内建进文件系统本身的需求,是 Btrfs 的世界观。

一句话概括两种设计哲学:XFS 延续「日志式文件系统」的传统,把并行度与规模做到极致,功能上克制,快照校验这些活留给 LVM 与外部工具;Btrfs 用写时复制的 B 树重造了文件系统的底座,快照、校验和、压缩、多副本全是底座的自然产物,但写时复制也带来了写放大这个必须直面的代价。理解这两个名字之前,先理解这两条路线的分野,选型争论就清晰了大半。

还要校准一个常见印象:XFS 与 Btrfs 都是内核主线里成熟的文件系统,XFS 是 RHEL 系发行版的默认根文件系统,Btrfs 在桌面发行版与不少 NAS 系统里担任主力。它们不是实验品,而是各有清晰生态位的正式选手。真正的问题从来不是「哪个更先进」,而是「哪种世界观匹配你的负载」。

判断负载属于哪个世界观,有三个现成的问题。第一问:数据怎么写——顺序追加为主还是随机覆写为主,前者两种文件系统都友好,后者是写时复制的逆风局。第二问:要什么功能——快照、校验、压缩是硬需求还是锦上添花,硬需求直接把票投给 Btrfs 或上层卷管理。第三问:谁来运维——团队对分配组、条带对齐、例行校验这些概念的熟悉程度,决定了选型的可持续性。三问答完,选型自然浮现,剩下的只是参数细节。

XFS:分配组与延迟分配撑起的并行 IO

XFS 起源于 SGI 时代的 IRIX 系统,进入主线多年,血统里刻着「大型图形与科学计算的大文件高吞吐」基因。它最核心的结构是分配组:把整个文件系统切成多个相互独立的区域,每个分配组各自维护空闲空间与 inode 的 B+ 树。并发写多个大文件时,不同线程落在不同分配组上,元数据分配互不串行,锁竞争天然分散——这是 XFS 在大阵列上并行 IO 强项的结构性根源,也是它区别于 ext4 全局锁模型的立身之本。

延迟分配是第二个支柱。应用 write 时,XFS 先只记账不定位,把脏页攒在内存里,等回写时再根据此刻全局的空闲空间分布,一次性分配大块连续的 extent 落盘。这让碎片控制拥有全局视野:随机小写的应用,最终也能在盘上攒出大而连续的数据块。代价是回写前数据只有内存副本,崩溃窗口更长——所以关键数据照旧要靠 fsync 语义保障,这与第 4 篇讲的页缓存纪律完全一致。

日志方面,XFS 默认记录元数据变更,日志区大小与缓冲个数在 mkfs 时可调,fsync 密集的数据库负载可以通过加大日志缓冲获得可观提升。值得一提的是 reflink 特性:文件级写时复制,cp 一条命令对几十 GB 的镜像做「秒复制」,数据库恢复演练、虚拟机镜像克隆都是受益场景;rmap 反向映射则让坏块定位与迁移更精准。在线扩容是 XFS 的老牌强项, growfs 直接撑大挂载中的文件系统,配合 LVM 是运维标准动作。mkfs 时用 agcount 控制分配组个数、按阵列条带参数设置对齐,是性能敏感场景的两个必调项。

XFS 的弱项也要如实说:海量小文件场景历史上不如 ext4 顺手(海量 inode 的创建与查找开销偏高),虽然近年已大幅改善,但邮件目录、代码仓库这类极端小文件负载仍建议实测对比;快照能力依赖 reflink 或外部卷管理,原生没有像 Btrfs 那样的一键快照语义;误删恢复工具链也不如 ext4 丰富。工具链上记住三件套:xfs_info 看布局参数、xfs_db 做底层检查、xfs_repair 做崩溃后修复,后者必须在卸载状态下运行。

分配组的调参值得展开。分配组个数默认随容量自动,但大阵列上手动设定常有惊喜:太多则每组元数据过散、空间利用率下降,太少则并行度不足;经验上让组数与预期的并发写线程数量级相当,每组仍保有足够的空间粒度。条带对齐同理:格式化时把条带单元与宽度喂给文件系统,延迟分配在落盘时按条带边界切大块,避免跨条带碎写。这两个参数都只在格式化时定型,事后改不了——大存储上线前的格式化参数评审,是 XFS 运维价值密度最高的半小时。

Btrfs:把快照与校验内建进文件系统

Btrfs 的底座是一棵棵 B 树:设备与块分配在 chunk 树,文件内容与目录结构在各自的文件树,全部数据的校验和在专门的校验树,连快照都只是树根的引用复制。所有数据与元数据的写入都走写时复制:修改一个块,先写到新位置,再自底向上更新指向它的父节点,树根指针换新。这个设计的直接产物是惊人的功能密度——快照瞬间完成(只是多了一个树根引用),子卷可独立挂载与配额,btrfs send 与 receive 能基于快照差量做增量备份,一条流水线替代传统备份软件的半壁江山。

数据完整性是第二个自然产物。每个数据块写入时计算校验和存入校验树,读取时逐块校验;配合多副本(单盘双副本或多盘镜像),读到坏块时可以从好副本取数并重写修复——自愈是文件系统的内建行为,不需要外部巡检。再加上透明压缩(zstd、lzo 可按子卷或文件启用),文本与日志类数据省一半空间并不稀奇,压缩还顺带降低了写盘量。定期跑 btrfs scrub 做全盘校验巡检,是 Btrfs 主机的例行保养。

但写时复制的代价同样结构性地存在。随机覆写在 CoW 下变成「读旧块、写新块、更新树」的三步操作,写放大数倍于就地覆写;碎片随时间持续恶化,长跑机器的顺序读性能会缓慢下降,btrfs defrag 是日常保养的一部分。多盘冗余上,RAID5 与 RAID6 模式长期存在写洞等一致性难题,社区多年明确不推荐生产使用,多盘冗余应选 RAID1 或 RAID10,或者把 Btrfs 架在 dm 层硬件 RAID 之上。balance 操作对使用率高的盘阵是重量级维护动作,要在业务低峰规划执行。

工程上最锋利的一把刀是 nodatacow:对指定文件或目录关闭数据块的写时复制,让随机覆写回到就地写路径,代价是这些文件失去校验和与压缩能力。这是 Btrfs 承认自身局限的诚实设计——它清楚 CoW 不是所有负载的答案,于是把选择权交还给管理员。

Btrfs 的日常巡检与应急再补几笔。全盘校验巡检后台跑、不中断服务,多副本机器上顺手完成自愈,建议纳入月度维护;设备级错误会在内核日志留下明确痕迹,配合监控告警能在用户感知前发现坏块。出问题时文件系统检查先用只读模式诊断,修复模式务必在离线状态下运行——写时复制文件系统的在线修复风险与日志式不同,纪律更严。快照链也要管理:快照免费但不是免费的无限量自助,链太长会拖慢删除与平衡,定期清理过期快照是卫生习惯。

CoW 的写放大与 nodatacow 抉择

把 CoW 的写放大算细。文件系统里一次 4KB 的随机覆写,在日志式文件系统上是一次数据写加一次日志记账;在 Btrfs 上则要写新数据块、可能重写其所在的叶节点、向上传播到中间节点甚至树根,加上校验树的更新,一次逻辑写放大成多次物理写。对 SSD 这不仅消耗寿命,也拉低有效吞吐;对数据库这种以随机写为主食的负载,性能落差可以达到数倍。文件追加场景则相反:CoW 对顺序追加友好,每次追加都落在新块,日志型负载在 Btrfs 上表现不差。

数据库在 Btrfs 上的标准姿势因此是:数据目录用 chattr 加 C 标记(即 nodatacow),换回就地覆写与正常 fsync 语义。要注意 nodatacow 只对「不与已有快照共享块」的新写生效——目录里有快照时,写时复制仍在树的层面发生,这是配置时常见的坑。虚拟机镜像、消息队列存储目录同理:凡是随机覆写密集的目录,都该考虑 nodatacow。反过来说,如果你的数据天生只追加、需要快照与校验(日志归档、备份仓库),开着 CoW 就是正确答案。

fsync 成本在两种文件系统上的分布也不同。XFS 的 fsync 主要落日志与延迟分配后的 extent 回写,数据库久经考验;Btrfs 开着 CoW 时,fsync 要连带落树与校验,成本更高,nodatacow 之后才回到常规水平。这条差异决定了同一套数据库压测在两种文件系统上的成绩不可直接换算——文件系统层调参(对齐、日志大小、CoW 开关)本身就是压测变量的一部分。

一组合成对比帮助建立直觉:顺序写大日志文件,Btrfs 开写时复制与 XFS 的吞吐差距通常很小,追加型写双方都友好;随机覆写混合读写,开写时复制的 Btrfs 写吞吐可能只有 XFS 的一半甚至更低,关掉数据写时复制后回到接近的水平;快照创建,Btrfs 毫秒级完成,XFS 要靠 reflink 或卷管理层配合,仍略慢于树根引用。这张草图的意义不是给数字,而是给量级感:负载形态决定一切,压测自己的访问模式,比背任何通用结论都可靠。

生产选型决策树

给一份可执行的决策树。默认与通用业务:ext4 或 XFS 任选,RHEL 系发行版跟默认走 XFS;容量阵列、大文件高并发、多媒体存储、数据库裸盘:优先 XFS,分配组并行与延迟分配正是为它们而生。需要快照回滚、增量备份、单机多副本校验、透明压缩的备份服务器与 NAS:Btrfs 上场,功能密度无可替代;桌面系统想要「误删前一刻」的安全网:Btrfs 快照配定时任务是最省心的方案。

数据落在 Btrfs 时的三条纪律:随机覆写密集目录(数据库、虚拟机镜像)一律 nodatacow;多盘冗余只用 RAID1 或 RAID10,别碰 RAID5 与 RAID6;把 defrag 与 scrub 纳入例行维护窗口。数据落在 XFS 时的两条纪律:mkfs 时按阵列条带对齐并规划分配组个数;xfs_repair 前必须卸载文件系统。跨场景通用的一条:任何文件系统迁移都要先在目标负载上压测 fsync 密集路径,文件系统层的差异只有在你自己的负载 profile 里才算数。

迁移与混部也有一句话指南。ext4 到 XFS 的迁移基本无痛,语义相近、工具链成熟,停机窗口做离线拷贝即可;迁到 Btrfs 则是范式切换,写时复制开关、快照策略、校验例行都要重新设计,值得单独立项。混部环境(同一台机器既有数据库又有普通业务)倾向把不同负载放进不同文件系统甚至不同分区:数据库盘 XFS 或 ext4,备份盘 Btrfs 吃快照红利,互不迁就。文件系统选型从来不是全局一票,而是按卷、按负载逐个决策的工程题。

小结

XFS 与 Btrfs 代表了 ext4 之外的两种世界观:前者把日志式文件系统的并行度做到极致,分配组与延迟分配撑起大阵列上的高吞吐;后者用写时复制的 B 树把快照、校验、压缩、增量备份内建成文件系统的自然产物。它们不是竞争关系,而是不同需求维度的各自最优。

CoW 是理解 Btrfs 的钥匙:快照与自愈是它的产物,写放大也是它的产物。nodatacow 给了随机写负载一条退路,也让「哪些目录开 CoW」成为 Btrfs 运维的核心决策。XFS 则用克制换稳定,把功能留给自己,把灵活留给卷管理层。

选型的正确姿势是按负载画像对号入座:规模与并行找 XFS,快照与完整性找 Btrfs,通用与稳妥找 ext4。三个名字背后其实是同一个问题的三种答案——你的数据以什么方式被写入、被读取、被保护。

← 返回资讯列表

读者留言

COMMENTS 暂无
仅本站原创文章开放留言 · 请勿留下手机号、邮箱等个人信息

还没有留言,来说第一句?