现代存储范式:COW 文件系统、LSM 树与对象存储
超越"原地更新 + 日志"的经典范式,现代存储走出三条路线:COW 文件系统(btrfs/ZFS)用永不原地写换取快照与校验和,LSM 树(LevelDB/RocksDB)用顺序写换取极致写吞吐,对象存储(S3/GFS/Dynamo)用扁平键空间与冗余副本服务海量数据。
一句话定义
超越"原地更新 + 日志"的经典范式,现代存储走出三条路线:COW 文件系统(btrfs/ZFS)用永不原地写换取快照与校验和,LSM 树(LevelDB/RocksDB)用顺序写换取极致写吞吐,对象存储(S3/GFS/Dynamo)用扁平键空间与冗余副本服务海量数据。
为什么重要
今天的数据库(RocksDB 引擎)、云存储(对象存储桶)、容器镜像(overlayfs 是 COW 思想)、甚至手机相册的"秒回退",全是这三条路线的工程化产物。它们共同的出发点是 kp-022 的介质事实(顺序远快于随机)与 kp-024 的可靠性纪律,是"文件系统设计"向"存储引擎设计"的演进。
前置知识
kp-023(日志与原地更新模型);kp-024(崩溃一致性)。
核心概念
- COW(写时复制)文件系统:更新写新位置、改指针、旧版本保留——天然快照与校验和;代表 btrfs、ZFS、BtrFS 快照。
- LSM 树:内存 memtable 排序累积 → 满了刷成不可变 SSTable → 后台分层/分层压缩合并,写全顺序。
- Bloom filter:LSM 读路径的"可能存在"概率过滤器,避免逐层磁盘查找。
- 写放大(write amplification):实际写入量/逻辑写入量,LSM 压缩的主要代价。
- 对象存储:扁平命名空间(桶+键)、HTTP 语义、不可变对象、靠副本或纠删码保久度;GFS/Dynamo 是系统原型。
- 纠删码(erasure coding):用 k+m 分片编码替代 3 副本,以计算换存储成本。
原理与机制
LSM 的读写路径:
写: key -> WAL(保崩溃一致, kp-024) -> memtable(内存跳表) -> 满则冻结刷出 L0 SSTable
后台: L0 与 L1 合并去重 -> 下沉 L2/L3... (每层放大倍率固定, 顺序大块读写)
读: memtable -> Bloom(L0..Ln) -> 逐层查找; 新版本覆盖旧版本
代价: 写放大典型 10~30x; 读放大靠 Bloom 压回 O(层级)
COW: 更新 -> 写新块+新元数据树 -> 原子切换根指针; 旧树即快照; 定期清理(碎片化来源)
对象: PUT/GET/DELETE 不可变对象 -> 网关机散布副本/分片 -> 一致性用仲裁或最终一致(Dynamo 风格)
三路线的取舍矩阵:
| 范式 | 写 | 读 | 快照 | 代表场景 |
|---|---|---|---|---|
| 原地更新+日志(ext4) | 中 | 好 | 贵 | 通用 |
| COW(ZFS/btrfs) | 中(易碎片) | 好 | 廉价原生 | NAS/备份 |
| LSM(RocksDB) | 极快 | 中(Bloom 补偿) | 天然版本化 | 写密集数据库 |
| 对象存储 | 吞吐型 | 低延迟差 | 版本桶 | 海量归档/云原生 |
图示
LSM: 写入 -> [WAL][memtable] --刷--> L0 ---合并---> L1 ---合并---> L2 ...
(不可变SSTable, 越往下越老越大)
直观类比
LSM 像先往笔记本上乱序速记(memtable),页满就把这一页誊清归档(SSTable),定期把多页誊本合并成一本(compaction);查旧账先翻速记本,再从新到旧逐卷查,Bloom filter 像每卷书的目录提示"这卷肯定没有,跳过"。COW 像合同改版从不涂改原文,每次整份重印并在封面换新版号,旧版自动存档。
实例或案例
lsblk -f # 识别 btrfs/zfs 文件系统
btrfs subvolume snapshot / /snap0 # COW 秒级快照(实验环境)
btrfs filesystem df / # 数据/元数据分配概况
sqlite3 test.db "PRAGMA journal_mode=WAL" # 亲手把一个库切成 LSM 式日志思想
docker/podman inspect 镜像层数 # overlayfs 的 COW 层叠即镜像原理(连接 kp-029)
常见误区
- 认为 LSM 读"慢到不可用":Bloom filter 与层级设计把典型读压到个位数次磁盘访问,读密集场景选 B+ 树、写密集选 LSM 是默认分野。
- 认为 COW 没有碎片问题:反复小写会持续开辟新块,长期碎片化需要后台清理,ZFS 的写放大与 btrfs 的 balance 都源于此。
- 把对象存储当低延迟块设备用:其延迟与计费模型都面向吞吐型访问,随机小 IO 场景是反模式。
与其他知识点的关系
COW 思想与 kp-007 的页级 COW 同源;LSM 的 WAL 严格执行 kp-024 的纪律;对象存储与容器镜像层叠连接 kp-029 的云原生世界。
延伸阅读
O'Neil 1996 LSM 原始论文;GFS(SOSP 2003)与 Dynamo(SOSP 2007)两篇开山之作;《数据密集型应用系统设计》第 3 章。
自测题
- LSM 树为什么写快?用什么弥补读?
答:写全部转化为顺序追加(日志+memtable 刷盘),避免随机原地更新;读靠 Bloom filter 快速排除不存在层、并用后台压缩降低层数。
- COW 文件系统的快照为什么几乎免费?
答:更新只写新块并生成新元数据树,旧树原封不动,快照只是"保留旧根指针",无数据复制。
- 对象存储与文件系统接口的本质差异?
答:扁平的桶+键命名空间与不可变对象、无目录层级与局部更新,只能整对象替换,换取近乎无限的横向扩展与高久度。