装系统走到磁盘分区格式化那一步,满屏幕文件系统列出来,大部分人习惯性敲回车选 ext4。旁边其实一直趴着个 Btrfs,很多人扫一眼就直接跳过。它同样是负责把数据落进物理磁盘,脾气却跟老牌文件系统大相径庭。
说白了,这份脾气全由底层的一个写盘动作决定。Btrfs 改文件从来不在原地覆盖,而是先找一处空白盘区把新内容写好,再把上层的指针移过去,老内容安稳留在原地。就这么一个简单的动作,既买来了它所有的看家本领,也欠下了后面的全部账单。琢磨透这笔交换,一行命令都不用记,就能看明白它怎么一步步演进到现在的形态,2026 年手头的机器到底该不该选它,心里自然有数。
看懂 Btrfs 得把视线拉回 2007 年,看看当年 Linux 存储到底在为哪些麻烦事发愁。那时候整个社区眼前摆着几块难啃的心病。
最直接的刺激来自隔壁阵营。2005 年 Sun 推出 ZFS,把快照、数据校验、多盘存储池这几项分散的功能整合成一层,整个存储业界为之震动。Linux 这边眼馋归眼馋,偏偏 ZFS 的许可证和 Linux 内核不兼容,代码没法并入主线,头顶还顶着专利风险。当时内核核心开发者 Andrew Morton 甚至公开批评这种设计是层次违规,这句话经 OSNews 转述才流传开来。想要类似的本领,Linux 只能挽起袖子自己从零造。
另一块心病是全盘检查太耗时间。文件系统在磁盘上记账,突发断电容易把账目搞乱,重启就必须跑一遍全盘检查才敢继续用。磁盘容量年年见涨,检查耗时跟着水涨船高。这亏 Linux 社区早就吃过一次:后来主导 ext4 开发的 Ted Ts’o 回忆,早在 2000、2001 年,40 到 80GB 的磁盘就扫得人发狂,社区的一片呼声直接催生出带日志的 ext3,断电后靠回放日志省去全盘检查。可这招只省掉了检查这一步,更深处的问题没动:ext 家族只负责账本元数据对不对,从不管文件内容本身;硬盘要是悄悄吐出损坏的数据,只要格式合规,系统完全没有手段察觉。
还有一套折磨人的麻烦是积木拼装。想用快照得靠 LVM 在底层划逻辑卷,想做多盘冗余又得加一层 md 组阵列,文件系统再扣在最上面。三层各自为政,互相并不知情。当时论坛评论留着一份操作清单:日常调个分区大小,得先卸载、跑检查,接着缩文件系统、缩逻辑卷,连敲四五个命令,还得祈祷两个工具对容量数字的换算别打架。
2007 年 11 月,各家公司的文件系统工程师坐到一起开工作坊,台上的直接由头就是 ZFS 铺天盖地的营销攻势。大家当场定了两条路:短期给 ext3 加扩展,做成次年才转为稳定版本的 ext4;长期另起炉灶,做支持快照和校验的新文件系统。短期这条路后来确实兑现了:ext4 能把 ext3 上要跑 45 分钟的检查压到 4 到 5 分钟,可文件内容本身依旧没人看管,这正是长期路线要补的洞。选来选去,挑中了 Oracle 工程师 Chris Mason 刚刚起步的 Btrfs。Ts’o 在会上给所有人泼了冷水,直言一个企业级文件系统要 50 到 200 人年、五年日历时间,ZFS 本身也是 2001 年动工、2006 年才端出来的。当时大家生怕吓跑金主投资,都拍胸脯说两三年就能搞定。后来 Ts’o 回顾结果,各发行版直到 2012 年秋天核准消费级可用,算下来一天没少,正好五年。
Btrfs 所有的机制都从一个动作起步:改文件,不去覆盖硬盘上的旧数据。它每次修改,都是先把改动后的内容写进空白位置,等数据全部落盘,再把指向它的入口指针改过去。这种写法叫写时复制,先写新的,再移指针。指针没挪过去之前,原先的数据原封不动;指针一旦切过去,新内容立刻生效。旧数据就安稳留在原处,直到再也没有任何地方引用它。
写入方式这么一变,快照立刻变得跟白送一样轻松。所谓快照,无非是给文件系统在某一瞬间存个状态,方便以后随时跳回来。传统的做法要么把数据硬拷贝一份,要么靠 LVM 在底层战战兢兢预留空间切卷。Btrfs 做快照只需要新建一个索引入口,指向现成的数据块,盘上的实体数据一个字节都不用搬。官方文档原话就是:the snapshot is instantaneous and only creates a new tree root copy。
伴随这个写盘动作,坏数据当场暴露。每个数据块落盘前都会算出一串校验值,如同给内容盖上钢印;读数据时重新算一遍,数值对不上马上报错。老 ext 家族没有这套机制,硬盘默默返回损坏的数据,系统会毫无知觉收下,甚至顺手打包进备份文件。有了钢印,脏数据就休想混进备份链条。不过要想把坏块修好,手里得有另一份完好的副本;单盘环境只有一份数据,校验机制负责把问题大声喊出来,修复则必须等冗余副本就位。
在线挪动磁盘也顺理成章。它的索引结构里自带反向引用,文件系统随时清楚每个数据块具体躺在哪块物理盘上。日常想加盘、拔盘、扩容或者缩小分区,直接在线执行就行,不需要折腾三层工具费力接力。
妙处在于,快照、校验、压缩和多盘管理这些特性全部挂在同一条写入路径上。这正是它跟老式拼装方案的分水岭:拼装方案是三套工具各管一段,Btrfs 则是一层统管,所有能力全从同一个写盘动作里流淌出来。
回头看 2007 年那三个卡点,病根全是原地覆盖写:新内容一落盘,旧状态就没了。旧状态留不住,快照只能靠外层工具先抄一份;校验找不着统一点,只能各做各的;分配权不在手里,多盘只能外面再包一层。Btrfs 改掉了这个默认行为。旧数据不销毁,旧状态仍躺在盘上,快照只需新建入口指过去;所有对象走同一条写路径,校验一次挂上全局生效;分配权收归自身,加盘拔盘在线就能做;突发断电后账本要么停在旧入口、要么切到新入口,理论上不存在半新半旧,ext2 时代那种全盘检查从原理上不再需要。三个解法全来自这同一个动作的兑现。
别把这笔交换记成 Btrfs 优化写、ext4 优化读的对称。准确的账是:Btrfs 用读取的局部性,换落盘的历史。写入当下反而更快,因为永远挑连续空位落笔;吃亏的是反复修改的大文件回头读,数据块散落一盘。ext4 并未参与这笔交易:原地覆盖,文件落在哪就待在哪,两头都不付账,它没有校验、快照与内置多盘,当年也未曾竞标这些。这也解释了为什么数据库跑在 Btrfs 上最吃力:数据库自己管页的物理布局,写时复制偏偏冲散了这套布局,后面的性能开关 +C 就是为此准备的豁免通道。
天下没有免费的午餐。换来这些好处的同时,写盘动作也签下了一串账单,每一笔都是这个机制带来的直接后果,可别把它们看成孤立的偶发毛病。
最先找上门的是磁盘碎片。旧数据不覆盖,新数据落新地,频繁改动的文件切片很快就七零八落散在盘上各处。官方手册自己承认:In COW filesystems, files tend to fragment as they are modified。Mason 自己给过解释(2015 年 NYLUG 演讲的 YouTube 自动字幕):写入因为只挑连续空地反而更快,但代价全压给了后续的读取;数据库原本为顺序读精心规划的物理布局,全搅成一团乱麻。虚拟机镜像、数据库还有经常原地改写的大文件,都是替这笔账买单的常客。
再看空间管理,它把磁盘分成了两本账。放文件实体的块组一块大约 1GiB,放目录结构的块组一块大约 256MiB,彼此分开核算。这就会引发一种让人摸不着头脑的怪事:明明显示磁盘还有剩余空间,存东西却报空间不足,原因其实是目录结构那本账先用光了。这时候想删几个大文件腾地方,偏偏删除操作也得写目录,结果连删文件都删不掉。这属于机制带来的正常逻辑,官方文档至今建议每卷留出 10GB 余量,快照控制在 12 个以内。
断电后的表现形式同样棘手。写时复制能保证账本完整,前提是物理硬盘按部就班遵守写入顺序。账本不乱并不代表开机就能顺顺当当:要是索引树出了差错,开机直接挂载失败跌进救援终端,需要输入专门的命令去修复。平时大家几乎不接触救援环境,真遇到了容易抓瞎。2025 年夏天出现过一波集中踩坑,一个潜伏挺久的 bug 在内核 6.15.3 变得非常容易触发,断电重启卡死在日志回放阶段。维护者确认了问题,主线修复排进 6.17,Fedora 也在 6.15.9 的补丁包里关闭了对应工单。这类问题露在用户眼前的样子足够反常:硬件和性能看着都好好的,偏偏就是进不去系统。
性能调节开关也是个暗坑。针对数据库或虚拟机文件打上 +C 属性,能关闭写时复制,随机写入性能马上回血。官方文档明确注明:加了这个标记,系统会连带停掉这批文件的数据校验。你想,为了抢性能,反而在最怕静默损坏的大文件上把刚换来的钢印给摘了。systemd 默认给系统日志目录加 +C,虚拟化组件 libvirt 也常给虚拟机镜像加,好多人对此浑然不觉。
至于多盘阵列欠下的那笔债,牵涉更多,得单独拉出来细说。里面的坑到现在都没能填平。
卷管理和文件系统合体之后,Btrfs 顺理成章获得了统领多块磁盘的权力。两块盘做镜像,两边各自留一份完整数据,哪边读出坏块就从另一边拉数据修复,校验机制在这里才算实现了完整的自愈闭环;多块盘也能切片条带化,把读写吞吐拉上去。然而它的野心不止于此,它还想把 RAID5/6 收入囊中,也就是通过奇偶校验让挂掉一块盘时能靠剩下的算回数据。偏偏这块硬骨头,到现在都没能啃利索。
翻开官方状态页(对应内核 7.1),RAID5/6 的栏目依然赫然写着 unstable,手册也直言 should not be used in production。问题的核心在 write hole 这个老毛病。遭遇意外断电,一条数据可能处于新旧各写了一半的状态,底层的校验码到底锚定哪一半谁也说不清。系统重新开机,很可能拿损坏的脏数据当成参考标准,反手把完好的数据给覆盖修坏了。想堵住这个漏洞,要么引入写日志,要么每次老老实实做全量读改写。当年全量读改写因为性能太差落选,写日志机制又迟迟没做出来。两头落空,漏洞便一直留到了现在。
官方版本史里关于 6.2 的复盘讲得直白:当年为了抢性能把读改写步骤直接砍掉,成了日后所有可靠性隐患的源头。2023 年发布的 6.2 内核合入了一部分补丁,但 RAID6 仍有大量工作待完成;新的 stripe tree 架构已经进入实验分支,官方口径认为这条路线最终会解决现有问题。这笔设计初期欠下的技术债,到今天依然在分期偿还。
算上 2009 年合并进 Linux 主线的时间,Btrfs 这十几年走过的路活脱脱就是一张长长的补课单。断电时空间写满报错的问题,2010 年才收尾第一轮修复;管理空闲空间的缓存机制,2011 年拿出第一版,2016 年推倒重写成 B 树,到 2021 年才扶正为默认配置,最早的那套实现直到 2024 年才正式标为废弃。据双源转述,磁盘物理格式在 2013 年 11 月宣布稳定,自那之后创建的分区,后续新内核都能直接挂载。2023 年它在修多盘读改写逻辑,2025 年还在排查 6.15.3 的日志回放故障。
对照着这条时间线,也能明白为什么它早年口碑相当糟糕。2011 年前后,论坛上时不时能看到笔记本用户丢光整盘数据、或者空闲空间充足却写不进数据的求助。这些风波大部分集中在物理格式冻结的前后几年。2017 年 Red Hat 宣布把 Btrfs 挡在转正门外,到 RHEL 8 干脆整棵剔除,官方给出的口径是技术预览功能从未打算转正,通篇没提一句丢数据。早年那些糟糕体验确实存在过,只不过那些血泪史对应的旧代码,跟今天大家手头跑的版本隔了十多年的密集修补。
要拿捏选型尺度,还是得回到那个写盘动作。它的长处和短板本就是一枚硬币的两面,到底合不合适,全看日常需求是恰好用上它的特性,还是迎头撞上它的账单。
真能发挥它长处、可以闭眼选的,首推单盘系统盘。两大发行版已经用默认配置帮大家站台多年:SUSE 系列把系统盘默认设为 Btrfs,配合自动化快照,系统更新翻车了开机选前一天的镜像就能回滚,属于开箱即用的完整体验;Fedora 桌面版也默认使用 Btrfs,不过官方写得很清楚,系统不自带自动快照回滚,想用得手动配工具。发行版的默认选型往往最能说明问题。对那些经常折腾内核、驱动或者频繁大版本升级的机器,快照回滚能省下大把时间。两块盘组镜像同样省心,官方给的评级是 OK,坏块能靠镜像自动补全,自愈闭环这才完整。
容易踩雷、建议绕着走的场景也要心里有数。想搭 RAID5/6 阵列,踏踏实实用底层传统阵列工具组好,上层直接格式化成普通文件系统,避开 Btrfs 原生阵列。承载数据库和虚拟机镜像的目录,要么默默承受碎片折磨,要么手动加上 +C 属性;顺便提醒一句,加了 +C 之后这部分文件就享受不到校验保护了。跑容器服务也没必要折腾存储驱动,官方文档写明即使底层在 Btrfs 上也建议继续用 overlay2。要是不想花心思理解两本空间账,日常使用也要留神,剩余容量读数容易产生误导,快照也会在后台不知不觉占满磁盘。
最后交代两句关于技术边界的实话。快照算不上备份,快照和原本的数据共用一套底层存储块,物理硬件损坏两边一起遭殃,官方文档一句话收尾:A snapshot is not a backup。校验码确实能揪出硬盘悄悄吐出的损坏数据,在有多余副本时把它救回来;但它拯救不了一块硬件故障无法读取的坏盘,更没法代替异地容灾;把错误找出来跟把数据修好,是两码事。
想通了底层写盘的这一笔交换,比死记硬背任何功能清单都管用。以后 Btrfs 再出新功能或者爆出新隐患,顺着这个核心动作一推就能明白原委。这个琢磨方式看别的底层软件同样行得通:摸清它最底层的那个关键动作,看它换来了什么本领、欠下了什么代价,后面的所有设计取舍自然一清二楚。