题记与说明
综合说明:本报告由两份分轴研究综合而成——纵轴《数据完整性工程(校验和、内容寻址、原子写入、文件锁与崩溃恢复)——纵轴发展历程》(1948–2026,六阶段)与横轴《数据完整性工程——横向对比报告》(2026-11-04 时间截面,五子领域 × 五维度),原始文件存于 parts/ 子目录。综合时完成了三类工作:①校准两章之间的矛盾与口径差异(共 5 处,逐条记录见文末附录"综合校准记录",含 BLAKE3 发布年份、SHA-1 碰撞佐证层级、BLAKE3 速度倍数两种口径等);②合并两章重复叙述的主题(flock/fcntl 语义分歧与三大锁史文献、SQLite WAL 双重叙述、FAST '10 ZFS 论文、BLAKE3 规格、Git SHA-256 现状),正文只详述一次,其余位置交叉引用;③新增"交叉洞察"一节,把纵轴的历史规律与横轴的当下格局结合成判断与建议。全部事实与数字保留原始出处链接;纵轴稿自述其事实经 2026-11-04 网络检索核对一手来源,横轴稿自述基于当日检索,两稿各自标注的"背景知识"处本综合沿用原标注,未新增未经来源的数字。定稿前按独立审读意见完成 8 条修订(引用出处核实、计数、术语定义、口径量纲与落地配方),逐条记录见文末附录二。数据截面:2026-11-04。
TL;DR
数据完整性工程由五个互相咬合的子领域构成:校验和发现损坏、内容寻址让哈希成为身份、原子写入让"写一半"不可见、文件锁让并发写入有序、崩溃恢复让断电后回到一致状态。纵轴 70 年:汉明码(1950)与 CRC(1961)奠基,LFS 与 ARIES(1992)确立日志恢复,2005 年 ZFS 与 Git 同年兑现端到端校验与内容寻址,2010 年 SQLite WAL 把日志带给大众,2015–2018 年连环事故把"fsync→rename→fsync 目录"钉成标准动作,2021–2026 年进入云默认校验、协议标准化与算力换代。横轴第一定律是三种语义分开买:完整性、原子性、持久性由不同机制、不同档位提供,事故根源几乎都是"以为买了 A,实际只买了 B"——rename 不 fsync、WAL 默认 NORMAL、CRC32C 防不了篡改。选型口诀:防随机错用 CRC32C/XXH3,防篡改用 SHA-256/BLAKE3;小文件替换用库封装的原子舞步,结构化状态直接上 SQLite/LMDB,进程互斥优先内核锁。五子领域咬合成体系,不存在单点最优。
一、纵轴:发展脉络(1948–2026)
主线一句话:数据完整性工程不是一项单一技术的编年史,而是五条子技术线在 70 余年间的反复交汇——每一环最初都因一类具体故障而生(真空管翻转、磁盘静默损坏、断电撕裂、并发覆写、哈希攻破),每一次范式切换都由"旧防线被新故障打穿"触发,而贯穿全程的胜负手是 1984 年 Saltzer 等人提出的端到端论证:把完整性校验提到端点,而不是信任中间任何一层(End-To-End Arguments in System Design, MIT 原文 PDF|ACM DL)。
阶段一(1948–1979):数学奠基——从汉明码到 CRC 再到哈希树
- 1950 年 4 月,贝尔实验室的 Richard W. Hamming 发表《Error Detecting and Error Correcting Codes》(Bell System Technical Journal 29(2):147–160),提出 [7,4] 汉明码:4 个数据位配 3 个校验位,可自动纠正单比特错误。动因直接来自他 1940 年代末在贝尔实验室忍受打孔卡计算反复出错的经历。今天的 ECC 内存仍是汉明码家族的直系后代(论文 PDF(耶鲁课程镜像)|Wiley DOI|Internet Archive 扫描件)。
- 1961 年 1 月,W. Wesley Peterson 与 D. T. Brown 发表《Cyclic Codes for Error Detection》(Proceedings of the IRE 49(1):228–235),把循环码理论转化为可工程实现的循环冗余校验(CRC):消息被视为多项式、对生成多项式做模除。以太网帧的 FCS、ZIP/GZIP 的 CRC32 都是它的后代(纵轴稿检索确认;经典科普见 Terry Ritter《The Great CRC Mystery》,Dr. Dobb's Journal of Software Tools 11(2):26–34, 76–83,1986 年 2 月,作者站点全文)。
- 1979 年,Ralph Merkle 在斯坦福大学博士论文《Secrecy, Authentication, and Public Key Systems》中提出哈希树(Merkle 树):叶节点是数据块的哈希,父节点是子节点哈希的哈希,一个根哈希即可担保整棵树的完整性(背景知识,参见 Merkle tree - Wikipedia)。这为后来 BitTorrent 的分片校验、Git 的对象链、IPFS 与证书透明度日志提供了统一数据结构。
驱动因素:真空管与磁芯存储的错误率让"算得对"本身成为工程问题;纠错先长在硬件层,再逐层向上渗透。
阶段二(1970s–1988):事务恢复成为学科、磁盘学会自愈、文件锁诞生
- 1970 年代,IBM System R 等系统把"影子分页 + 前滚/回滚日志"用于事务恢复;Jim Gray 1978 年《Notes on Data Base Operating Systems》将事务的原子性与持久性系统化(背景知识,纵轴稿未单独检索原文)。
- 1983 年,4.2BSD 引入
flock(2)——整文件级、绑定"打开文件描述"的建议锁;System V 阵营的字节范围锁fcntl(2)则经 POSIX.1(1988)标准化。两套语义差异(描述符持有 vs 进程持有、整文件 vs 字节范围)埋下此后 30 余年"锁的便携性"争论(flock(2) man page|Apenwarr《Everything you never wanted to know about file locking》2010|0pointer.de《On the Brokenness of File Locking》)。System V 式"强制锁"(setgid 位技巧)也出现在这一时期,后来被证明充满竞态。 - 1988 年,UC Berkeley 的 Patterson、Gibson、Katz 在 SIGMOD 发表《A Case for Redundant Arrays of Inexpensive Disks》,提出 RAID 五级分类,用便宜盘阵列加冗余校验替代单一大盘(CMU 论文 PDF|ACM DL|Computer History Museum 评论)。
驱动因素:数据库把崩溃一致性列为硬需求;"更便宜但更会坏"的磁盘经济学;Unix 多用户并发催生锁机制。
阶段三(1990–2004):日志化文件系统、密码学哈希与增量同步
- 1992 年,Rosenblum 与 Ousterhout 发表《The Design and Implementation of a Log-Structured File System》(ACM TOCS 10(1)):把所有写入串成顺序日志、用 checkpoint 做崩溃恢复,是后续写时复制文件系统(ZFS/Btrfs/F2FS)与 LSM 树的思想源头(Stanford 论文 PDF|ACM DL)。同年 IBM Almaden 的 Mohan 等人发表 ARIES(ACM TODS 17(1)),把写前日志(WAL)恢复算法规范化为 Analysis/Redo/Undo 三阶段,成为 DB2 及 PostgreSQL 等系统恢复机制的蓝本(MIT 6.5830 课程材料|DBtech 讲义 PDF)。
- 密码学哈希走向实用:MD5(Rivest,RFC 1321,1992)、SHA-1(NIST FIPS 180,1995)、SHA-2(FIPS 180-2,2001)(背景知识)。哈希的用途开始从"检错"转向"认证与身份"。
- 1996 年 6 月,Tridgell 与 Mackerras 发布 rsync 算法技术报告:滚动校验和 + 分块哈希,只传输差异部分;Tridgell 1999 年 ANU 博士论文将其系统化(技术报告|博士论文|Wikipedia: Rsync)。滚动校验所用 Adler-32 由 Mark Adler 于 1995 年为 zlib 设计(背景知识)。
- 1998–2001 年,Stephen Tweedie 为 ext2 增加日志:1998 年发表《Journaling the Linux ext2fs Filesystem》,1999 年 9 月 ext3 发布,2001 年 11 月随 Linux 2.4.15 进入主线;journal/ordered/writeback 三种日志模式自此定型(论文 PDF|Wikipedia: Ext3)。同期 FreeBSD 阵营的对手路线是 McKusick 与 Ganger 的 soft updates(USENIX 1999;TOCS 2000 扩展版):不写日志,靠元数据依赖排序消除大部分同步写(USENIX 页面|TOCS 论文 PDF)。"日志 vs 依赖排序"是本阶段的核心技术辩论。
- 2001 年,MIT 的 LBFS 在 SOSP 发表《A Low-Bandwidth Network File System》:用 Rabin 滚动指纹做内容定义分块(CDC),块边界只取决于内容而非位置,重复数据自动去重——现代备份工具 restic、Borg 的去重内核即源于此(纵轴稿特别更正:LBFS 发表于 SOSP '01,常被误记为 2004)。同年 Bram Cohen 发布 BitTorrent(背景知识,Wikipedia):文件切成固定大小 piece、逐片哈希校验——哈希首次成为大众级分发协议的完整性骨干。
驱动因素:磁盘寻道与写性能的矛盾(→日志化)、互联网带宽稀缺(→增量传输与去重)、哈希算力普及(→内容身份)。
阶段四(2005–2013):端到端完整性落地、内容寻址登堂入室
理论支柱早已就位(1984 年端到端论证),2005 年起在存储与应用两侧同时兑现:
- 2005 年 11 月,ZFS 随 OpenSolaris 发布。Bonwick 与 Moore 的《ZFS: The Last Word in File Systems》把"端到端校验和"列为核心卖点:每个块的校验和存放在其父块(最终到 uberblock)中,能发现 bit rot、幻写、错址读写、DMA 校验错等整条 I/O 路径上的损坏(2005 演讲 PDF|Bryan Cantrill 博客《Welcome to ZFS!》|FAST '10 论文)。
- 同为 2005 年 4 月,BitKeeper 授权撤回后,Linus Torvalds 在 LKML 发布"Kernel SCM saga..",十天内写出 git,并明确将其定义为"内容可寻址文件系统 + 之上的 SCM 层"——每个对象以内容哈希寻址(Git - Wikipedia|The New Stack 20 周年回顾)。内容寻址自此从论文概念变成数十亿人日常依赖的基础设施。
- 2007 年 6 月,Chris Mason 在 LKML 公布 Btrfs——写时复制、快照、"为所有文件数据与元数据维护校验和"(原始公告),2009 年随 Linux 2.6.29 合入主线(LWN|Linux Foundation 访谈)。
- 2003–2006 年,Eelco Dolstra 开发 Nix:软件包存放于
/nix/store/<哈希>-名-版本,路径哈希由全部构建输入决定——不可变、可回滚、原子升级;2006 年 1 月博士论文系统化(论文 PDF|NixOS Research)。2003 年 Google 发表 GFS(SOSP 2003,背景知识见 Wikipedia):每个 64KB chunk 维护校验和,确立"大规模集群必须自带校验"的工业惯例。 - 2010 年 7 月 21 日,SQLite 3.7.0 引入 WAL 模式:读写不再互斥、崩溃恢复改为回放 -wal 文件(官方 WAL 文档|3.7.0 changelog)。SQLite 的《Atomic Commit In SQLite》文档本身也成为原子提交工程的事实教材(sqlite.org/atomiccommit.html)。
- 2013 年,Google 启动首个证书透明度(CT)日志,IETF 于 2013 年 6 月发布 RFC 6962:用仅追加的 Merkle 树日志让 TLS 证书签发可公开审计(RFC 6962|Wikipedia: Certificate Transparency)。同年 9 月,PostgreSQL 9.3 引入数据页校验和(
initdb --data-checksums,页级 CRC-16),把 ZFS 式校验带进单机数据库(EndPoint 博客|Paquier 笔记)。
驱动因素:磁盘容量增速远超带宽(校验与去重必须内建)、BitKeeper 事件、数据中心规模、1984 年端到端论证的工程兑现。
阶段五(2014–2020):事故驱动,"崩溃一致性"成为显学
- 内核补齐原子写入原语:2013 年 Linux 3.11 加入
O_TMPFILE(无目录项的临时文件,崩溃不残留);2014 年 Linux 3.15 加入renameat2(RENAME_EXCHANGE)原子交换两个路径(KernelNewbies Linux 3.11|LWN《Exchanging two files》|man7 rename(2))。 - 2015 年,Dan Luu 发表《Files are hard》,以断电实测证明"写临时文件 + rename"若不配对 fsync(含目录 fsync),在多种真实文件系统上仍会丢数据;2017 年续篇《Filesystem error handling》统计大量应用直接吞掉文件系统错误(Files are hard|Filesystem error handling)。
- 2017 年 2 月 23 日,Google 与 CWI Amsterdam 宣布 SHAttered:首例实用化 SHA-1 碰撞(两份内容不同而 SHA-1 相同的 PDF,约 6500 CPU 年算力);NIST 于 2 月 24 日正式弃用 SHA-1(shattered.io|CWI 新闻稿|NIST 回应)。此前 2004 年王小云团队已在 CRYPTO 大会宣布 MD5 碰撞,并于 EUROCRYPT 2005 发表《How to Break MD5 and Other Hash Functions》(Springer 章节)。
- 2018 年 3 月,PostgreSQL 开发者 Craig Ringer 曝出 fsyncgate 2018:内核把 fsync() 错误上报一次后丢弃、重试返回成功,PostgreSQL 因此"错误使用 fsync 达 20 年";事故推动多个系统重审 fsync 错误语义,PostgreSQL 随后引入
data_sync_retry(PostgreSQL Wiki: Fsync Errors|danluu.com/fsyncgate 邮件存档)。 - 这一切是对 2009 年"O_PONIES"之争的迟到回应:当年应用请求内核让 rename 后的数据自动持久化,被内核社区拒绝,共识随之固化——fsync 文件 → rename → fsync 目录 才是完整的持久化协议(LWN《POSIX v. reality: A position on O_PONIES》2009|LevelDB issue #195)。
- 2010 年代中期起,restic、Borg 等新一代备份工具把 LBFS 的内容定义分块加加密去重变成默认配置(背景知识;两者横轴对比见第二节)。2014 年 arXiv 首发的 IPFS 白皮书(Juan Benet)把 Git 的对象模型、BitTorrent 的块交换与 Merkle 链合成一个内容寻址网络(arXiv:1407.3561)。
- 2020 年 1 月 9 日,BLAKE3 发布(O'Connor、Aumasson、Neves、Wilcox-O'Hearn):基于 BLAKE2 与 BAO 树构造、面向多核并行与 SIMD、极快(Wikipedia: BLAKE)|BLAKE3 规格书 PDF|官方仓库)。2020 年 10 月 19 日,Git 2.29 引入实验性 SHA-256 仓库格式,正式回应 SHA-1 之死(Phoronix|GitHub Blog)。
驱动因素:SSD/FTL 带来新故障面、学术工作(UW-Madison 崩溃一致性系列等)与工业事故互相指认、密码学哈希进入"退役周期"。
阶段六(2021–2026):云默认校验、协议标准化与算力换代
- 2021 年 10 月 31 日,Linux 5.15 移除强制文件锁(
-o mand与LOCK_MAND),5.14 先行弹出弃用警告;建议锁(flock/fcntl)成为唯一正道——文件锁近 40 年演进以"做减法"收尾(KernelNewbies Linux 5.15|内核 5.14 changelog)。 - 2022 年 2 月 25 日,AWS 为 S3 新增 CRC32C/SHA-1/SHA-256/CRC32 校验选项(此前默认只有 MD5 系 ETag),其后进一步把 CRC32 设为未指定算法时的默认校验——对象存储把完整性检查变成零成本默认(AWS 官方博客|S3 用户指南|第三方分析)。
- 2022 年 12 月 15 日,NIST 宣布 SHA-1 应于 2030 年 12 月 31 日前全面退役(SP 800-131A 修订;Rev. 3 草案 2024 年 10 月给出时间表)(NIST 新闻|NIST 哈希政策)。
- 2024 年 2 月,IETF 发布 RFC 9530《Digest Fields》:
Content-Digest/Repr-Digest字段取代 2002 年 RFC 3230 的Digest——HTTP 表示层完整性第一次进入标准轨道(RFC Editor|共作者 Lucas Pardue 的解读)。 - 2025 年 1 月 13 日,OpenZFS 2.3 发布:BLAKE3 校验和(官方口径较 SHA-256 快至约 3 倍)、Fast Dedup、RAIDZ 扩容——2005 年的端到端完整性思想仍在自我换代(Phoronix)。
- 2025 年 9 月 25 日,PostgreSQL 18 发布异步 I/O 子系统(
io_method = worker/io_uring/sync),把读写/刷盘路径推进 io_uring 时代;2026 年在途的 PG 19 计划支持在线开关数据校验和(此前必须 initdb 时启用或用 pg_checksums 离线处理)(PostgreSQL 18 官方公告|pganalyze 深度分析|depesz: Waiting for PostgreSQL 19)。 - 证书透明度生态换代:2025 年 8 月 14 日,Let's Encrypt 宣布 RFC 6962 日志退役计划,转向 Merkle Tree Certificates 草案(Let's Encrypt 公告|IETF 草案)。供应链完整性普及:Sigstore(2021 年起)与 SLSA 等把"哈希 + 透明日志 + 证明"打包成软件供应链的完整性基线(背景知识);块级方向另有 SCSI T10 DIF/PI 与 Linux
CONFIG_BLK_DEV_INTEGRITY提供每扇区 8 字节保护信息的端到端方案(SBC-3 标准草案)。
驱动因素:云厂商把"默认校验"当作差异化能力;供应链攻击推高可验证性需求;硬件 CRC32C 指令与并行哈希让校验成本趋近于零;旧算法与旧语义进入集中退役期。
纵轴小结:贯穿 70 年的三条主线
- 故障模型下移,防御上移——端到端论证的反复胜出。从磁芯、磁盘到 DMA、FTL、固件,每一层都可能静默出错;单点校验(RAID、链路校验和)反复被"漏网"故障打穿,最终答案总是把校验提到端点:ZFS 的父块指针校验和(2005)、Git 的对象哈希(2005)、S3 的默认 CRC32(2022 前后)是同一论证在三个十年的重复兑现。
- "先日志、后改名、再锁"模式固化。LFS 与 ARIES(1992)确立 WAL 与三阶段恢复;ext3 与 SQLite WAL(2010)把日志带给大众;2009 年 O_PONIES 之争与 2018 年 fsyncgate 把"fsync 文件 → rename → fsync 目录"钉成跨平台标准动作;Git 的 lockfile 与 SQLite 的五态锁——即其回滚日志模式的文件锁状态机,按 UNLOCKED→SHARED→RESERVED→PENDING→EXCLUSIVE 五个状态演进(SQLite File Locking 文档)——则是"建议锁"哲学的样板。日志与写时复制两族(ext3/XFS 对 ZFS/Btrfs)在 2025 年的 OpenZFS 2.3 与 PG 18 io_uring 中依然并行演化。
- 哈希从检错到身份。CRC(1961)回答"传输出错没有";MD5/SHA-1(1991–1995)回答"内容可信吗",并在 2004(MD5 碰撞)与 2017(SHAttered)两次退位;SHA-2/SHA-3/BLAKE3 时代,哈希成为地址(Git、Nix、IPFS、OCI 镜像摘要)与账本(证书透明度、Sigstore)。内容寻址把完整性从"附加校验"升级为"身份即证明",这是 70 年里最大的一次范式迁移。
二、横轴:横向对比(2026-11-04 截面)
2.1 对比框架:三种语义必须分开买
"数据完整性工程"不是单一技术,而是五个互相咬合的子领域,每个子领域内部都存在多条竞争路线:
| 子领域 | 核心问题 | 主要竞争路线 |
|---|---|---|
| 校验和 | 怎么发现数据坏了? | CRC 系列 / xxHash / SHA-2 / BLAKE3 / 文件系统块级校验 |
| 内容寻址 | 怎么用"内容本身"当身份? | Git 对象库 / IPFS CID / 备份仓库(restic、Borg)/ 构建缓存 CAS(Bazel、Nix) |
| 原子写入 | 怎么保证读者只见完整的旧文件或完整的新文件? | temp+fsync+rename 手工舞步 / 语言库 / Windows 原语 / 内核 RWF_ATOMIC / 直接换嵌入式数据库 |
| 文件锁 | 怎么防止两个进程同时改一份数据? | flock / fcntl 记录锁 / O_EXCL 锁文件约定 / Windows LockFileEx / 跨平台库 |
| 崩溃恢复 | 断电/进程崩溃之后怎么把数据救回来? | rollback journal / WAL / Copy-on-Write B 树 / AOF 追加日志 / 文件系统日志 |
进入逐项对比前,先立一个贯穿全篇的框架——三种语义必须分开买:
- Integrity(完整性):数据没有被悄悄改坏(位翻转、静默损坏、篡改)——由校验和/内容寻址保证;
- Atomicity(原子性):状态切换要么全发生、要么全不发生——由 rename/RWF_ATOMIC/WAL 提交保证;
- Durability(持久性):进程返回"写入成功"后,即使断电数据也在——由 fsync/同步档位保证。
工程事故最常见的形态不是"没做数据完整性",而是以为买了 A,实际只买了 B。下文每个子领域都会回到这条线;纵轴的事故史(O_PONIES、fsyncgate、Files are hard)正是它的历史注脚。
2.2 总览矩阵(五子领域 × 代表方案 × 五维度)
| 子领域 | 代表方案 | 能力 | 成本 | 生态 | 成熟度 | 最佳适用 |
|---|---|---|---|---|---|---|
| 校验和 | CRC32C | 防随机错,不防篡改 | 硬件加速约 10–30 GB/s | 极广(网络/存储) | 数十年 | 传输帧、块设备 |
| 校验和 | xxHash (XXH3) | 防随机错,非加密 | AVX2 约 59 GB/s,AVX-512 可超 130 GB/s | 广(C/Rust/Go/Java) | 高(2012 起,XXH3 为 2019+) | 内存级去重、缓存键 |
| 校验和 | SHA-256 | 抗碰撞、防篡改 | 数百 MB/s | 极广 | 极高 | 签名、证书、内容寻址 |
| 校验和 | BLAKE3 | 抗碰撞 + 并行流式 | 单核约 2.4 GB/s,多核 AVX-512 约 10+ GB/s | 增长中 | 中高(2020-01-09 发布) | 大文件快速完整性校验 |
| 内容寻址 | Git 对象库 | hash=对象 ID,不可变 | 全量对象库有 GC 成本 | 开发者全员 | 极高 | 源码版本管理 |
| 内容寻址 | IPFS CID | 自描述多层标识符(multihash) | CID 结构有开销 | Web3/分发 | 高 | 去中心化分发、跨算法演进 |
| 内容寻址 | restic / Borg | CDC 分块 + 认证加密 | 去重与加密开销 | 备份圈主流 | 高 | 加密去重备份 |
| 原子写入 | temp+fsync+rename | 原子替换(POSIX) | 需正确处理 4 步舞 + 目录 fsync | 各语言均有库 | 极高 | 配置/状态文件更新 |
| 原子写入 | Linux RWF_ATOMIC | 块层"不断裂写"(硬件保证) | 需 NVMe/SCSI 硬件支持 | 内核 6.11+,ext4/XFS | 新兴(2024 起) | 数据库大页写入 |
| 原子写入 | SQLite / LMDB | 完整 ACID/快照 | 换抽象的复杂度 | 极广 | 极高 | 结构化状态存储 |
| 文件锁 | flock | 内核 advisory 锁,进程死自动释放 | 低 | Unix 系 | 数十年 | 单机多进程互斥 |
| 文件锁 | fcntl/lockf | 进程级字节范围锁 | 低,但"关任一 fd 即放锁"的坑 | POSIX 全平台 | 数十年 | 数据库/字节级锁 |
| 文件锁 | proper-lockfile 等 | 锁文件 + mtime 陈旧检测 | 需心跳/超时机制 | Node 生态 | 高 | NFS/跨平台场景 |
| 崩溃恢复 | SQLite WAL | 原子提交 + 并发读 | WAL 模式默认不防断电 | 极广 | 极高 | 嵌入式事务存储 |
| 崩溃恢复 | LMDB COW B+树 | 结构性免恢复(无需重放) | 写放大 | 广(OpenLDAP 原生孵化;Postfix、PowerDNS、Monero 等采用) | 高 | 读多写少的 KV |
| 崩溃恢复 | Redis AOF | 追加日志 + 三档 fsync | everysec 约 1 秒丢失窗口 | 极广 | 极高 | 缓存/弱持久 KV |
2.3 子领域一:校验和——"发现数据坏了"的六条路线
| 方案 | 类型 | 速度(单线程量级) | 对抗强度 | 生态与成熟度 | 适用场景 |
|---|---|---|---|---|---|
| CRC32 / CRC32C | 循环冗余校验 | 硬件加速(SSE4.2/ARMv8 CRC 指令)约 10–30+ GB/s | 无抗碰撞性,可被轻易伪造 | 网络协议、文件系统默认值,数十年 | 防传输/存储随机错误 |
| xxHash(XXH3/XXH128) | 非加密快速哈希 | AVX2 约 59.4 GB/s,AVX-512 实测超 130 GB/s,接近 memcpy | 非加密,不防对抗 | C/Rust/Go/Java/Python 绑定齐全 | 内存去重、缓存键、大文件快速比对 |
| MD5 / SHA-1 | 遗留加密哈希 | 中速 | 均已被实际攻破 | 存量巨大但新项目应弃用 | 仅遗留系统兼容 |
| SHA-256 / SHA-512 | 加密哈希 | 数百 MB/s | 抗碰撞,通用对抗标准 | 极广:TLS、Git、IPFS、证书链 | 防篡改、签名、内容寻址 |
| BLAKE3 | 加密哈希(Merkle 树结构) | 单核约 2.4 GB/s;多核 + AVX-512 可达 10+ GB/s,约为 SHA-256 的 15–27 倍 | 抗碰撞,流式/并行友好 | 2020-01-09 发布,各主流语言绑定增长中 | 大文件、大吞吐场景下的"真"完整性校验 |
| 文件系统块级校验(ZFS/Btrfs) | 端到端块校验 + 自愈 | 写入时算、读取时验,有冗余时可自愈 | 防静默损坏(bit rot、错位读写) | ZFS/Btrfs 生产广泛 | 存储层兜底 |
分组说明:六条路线按三层组织——速度层(CRC32/CRC32C、xxHash)、密码学层(MD5/SHA-1 为退役一代,SHA-256/SHA-512 与 BLAKE3 为现役两代)、存储层(ZFS/Btrfs 块级校验),下文按层展开。
速度层(CRC32C 与 xxHash):xxHash 官方基准显示 XXH3_64 在 AVX2 机器上约 59.4 GB/s,AVX-512 平台实测超过 130 GB/s,逼近甚至超过内存拷贝带宽(xxhash.com 基准);CRC32C 依靠 CPU 硬件指令也能达到 10–30 GB/s 量级。但两者都不具备抗碰撞性——它们防的是宇宙射线般的随机位翻转,不防恶意篡改(xxHash vs BLAKE3 对比、CodeSector 校验和格式指南)。
密码学层(SHA-256 与 BLAKE3):SHA-256 是"防篡改"的通用答案,但速度只有数百 MB/s;BLAKE3 用 Merkle 树结构把加密哈希做到单核约 2.4 GB/s、多核 AVX-512 下约 10+ GB/s,官方仓库口径约比 SHA-256 快 15–27 倍(xxHash 仓库基准讨论 #660、BLAKE3 官方仓库)。注意速度倍数存在两种口径:裸哈希多核并行下 15–27×(BLAKE3 官方基准),文件系统集成场景下 OpenZFS 2.3 官方口径约 3×(Phoronix)——集成开销与 I/O 瓶颈会吃掉裸哈希优势。MD5 与 SHA-1 已被实际攻破(SHAttered,2017-02-23,一手来源见纵轴阶段五),新系统应弃用。选型口诀:防随机错用 CRC32C/XXH3,防人(对抗)用 SHA-256/BLAKE3,两者不可互相替代。
存储层(ZFS/Btrfs 端到端校验):UW–Madison 在 FAST '10 的经典论文《End-to-end Data Integrity for File Systems: A ZFS Case Study》证实 ZFS 能有效检测静默损坏(bit rot、幻影写、错位读写),但也指出了磁盘与内存之间传输的盲区(论文 PDF)。ZFS 对数据与元数据全量校验,有镜像/RAID-Z 冗余时可自愈并支持 scrub 全盘巡检;而 ext4/NTFS 默认不校验数据内容,可能把坏数据静默返回给应用(Btrfs vs ZFS 对比)。Btrfs 默认 CRC32C,但支持切换 xxhash/sha256/blake2 等更强算法。关键提醒:没有 ECC 内存时,连 ZFS 也无法闭环——内存里的损坏发生在校验计算之后(Reddit r/zfs 讨论)。
横轴结论(校验和):2026 年的格局是"三层分工"——硬件(CRC32C 指令、ECC)负责便宜的随机错检测,文件系统(ZFS/Btrfs)负责端到端兜底,应用层用 BLAKE3/SHA-256 负责"我 care 的那份数据"的强校验。xxHash 与 BLAKE3 的出现让"快"与"强"不再必须二选一——这是近五年该子领域最大的格局变化。
2.4 子领域二:内容寻址——"内容即身份"的六种实现
| 方案 | 寻址单位 | 哈希算法 | 标识符自描述性 | 去重 | 防篡改 | 生态/成熟度 | 典型场景 |
|---|---|---|---|---|---|---|---|
| Git 对象库 | 对象(blob/tree/commit) | SHA-1(历史)/ SHA-256(可选) | 无(算法固定于仓库) | 天然按内容去重 | 依赖哈希 + 签名 | 开发者全员,极高 | 源码版本管理 |
| IPFS CID | 任意块(blob/chunk) | 默认 sha2-256,multihash 可扩展 | 强(multibase+版本+multicodec+multihash) | 按 CID 去重 | 哈希即校验 | Web3/分发领域成熟 | 去中心化分发、算法可演进场景 |
| restic | CDC 分块 | 加密后 SHA-256 | 中 | 内容定义分块去重 | 认证加密(防篡改+防泄漏) | 备份圈主流 | 加密去重备份,任意后端 |
| Borg | CDC 分块 | 分段 CRC32 + 加密 | 中 | 存储效率口碑更强(去重 + 可调压缩) | 认证加密 | 备份圈主流 | 高压缩比、同机仓库 |
| Bazel 远程缓存(CAS) | 动作输入/输出 | SHA-256 | 中(协议化) | 天然去重 | 依赖哈希 | 构建系统标配 | 构建加速 |
| Nix / OSTree 存储 | 包/文件树 | SHA-256 | 中 | 不可变存储 + GC | 不可变性 | DevOps 成熟 | 可复现部署、系统树版本化 |
分组说明:六种实现归为四类展开——版本管理(Git)、去中心化分发(IPFS)、备份仓库(restic 与 Borg 合算一路)、构建与部署(Bazel CAS 与 Nix/OSTree 合算一路)。
Git 对象库:哈希即对象 ID,内容寻址的最小可行实现。历史上固定 SHA-1;2020 年 10 月 Git 2.29 引入实验性 SHA-256 对象格式(Phoronix),社区计划在 Git 3.0 设为默认,但痛点在存量仓库与生态——SHA-1 与 SHA-256 仓库之间至今无法互相 push,主流托管平台尚未支持 SHA-256 仓库,第三方工具又常假定 40 字符哈希;LWN 记录互操作补丁自 2020 年提出后始终未合入、Git 2.31(2021-03)后再无实质进展,维护者甚至直言"暂不建议用于正经项目"(LWN: Whatever happened to SHA-256 support in Git?)。这暴露了内容寻址系统的通用难题:哈希算法写死在标识符里,升级即意味着迁移。
IPFS CID:与 Git 相反,CID 被设计为自描述标识符——multibase 编码 + 版本号 + multicodec 内容类型 + multihash(算法自描述),因此哈希算法可以逐标识符演进而不破坏系统,默认算法为 sha2-256;注意 CID 不是裸哈希,sha256sum 的输出与 CID 不一致(IPFS 官方文档:Content Addressing、CID 规范、Filebase: CID 结构拆解)。这是 Git 与 IPFS 最本质的架构分歧:固定算法换简单 vs 自描述换可演进。
restic 与 Borg(备份即内容寻址):两者都用内容定义分块(CDC)做去重(思想源头即纵轴阶段三的 LBFS,SOSP '01),都用认证加密保证"篡改可检测"——restic 使用 AES-256-CTR + Poly1305 / ChaCha20-Poly1305。差异在:Borg 在存储效率上口碑更强(分块更细 + lz4/zstd/zlib/lzma 可调压缩),但通常要求远端主机装有 Borg 二进制;restic 的仓库可放在任意通用后端(S3、SFTP 等),默认 zstd 压缩后与 Borg 的效率差距在常见数据上已明显缩小(restic vs Borg 对比、Borg check 文档)。borg check --verify-data 做全量数据校验,而默认只校验分段 CRC32(restic 论坛:CDC 去重的安全性讨论)。
构建与部署侧(Bazel CAS、Nix、OSTree):Bazel 远程缓存由两部分组成——action cache(动作哈希 → 结果元数据映射)与 content-addressable store(Bazel 官方文档:Remote Caching、EngFlow: The Many Caches of Bazel);开源实现 bazel-remote 直接以小写 SHA-256 为键的扁平不可变存储(bazel-remote)。Nix store 与 OSTree 同属"不可变哈希寻址存储 + GC"的部署流派(横轴稿标注:此句部分基于模型既有知识归纳,检索以 Bazel 侧为准;Nix 的原始出处见纵轴阶段四的 Dolstra 博士论文)。
横轴结论(内容寻址):内容寻址 = 完整性 + 去重 + 不可变性三合一,是"校验和"子领域的自然延伸。但它只保证读路径的完整性:写入中断产生的半成品对象要靠原子写入兜底(衔接 2.5 节);对象引用关系形成的图需要 GC,而"正在被引用"的判断又需要文件锁(衔接 2.6 节)——五个子领域在此咬合。
2.5 子领域三:原子写入——从"四步舞"到硬件原子
| 方案 | 原子性保证 | 持久性手段 | 跨平台 | 成熟度 | 适用场景 |
|---|---|---|---|---|---|
| temp+fsync+rename 手工模式 | POSIX rename 原子替换 | fsync 临时文件 + fsync 目录 | POSIX 系(Windows 需另换原语) | 极高但正确实现稀少 | 配置文件、状态文件更新 |
| 语言库(write-file-atomic / os.replace / rust-atomicwrites) | 同上,封装正确细节 | 库内处理 fsync | 多数覆盖双平台 | 高 | 应用层默认选择 |
| Windows MoveFileEx / ReplaceFile | NTFS 上原子替换 | MOVEFILE_WRITE_THROUGH | Windows | 高 | Windows 端原子替换 |
| Linux RWF_ATOMIC | 块层"不断裂写"(单次 I/O 原子) | 硬件保证,随写随持久语义 | Linux 6.11+,需 NVMe/SCSI 支持 | 新兴(2024–2025) | 数据库大块写入 |
| SQLite / LMDB | 事务级 ACID/快照 | WAL/journal/COW 全套 | 极广 | 极高 | 结构化状态,"别手写舞步"的替代 |
POSIX 四步舞及其陷阱:标准模式是 ① 同目录写临时文件(保证同文件系统,rename 才原子)② fsync 临时文件 ③ rename 覆盖目标 ④ fsync 目录(保证 rename 本身落盘)。这条要求写进了手册页:fsync(2) 明确指出"调用 fsync() 并不保证文件所在目录的目录项也已落盘,为此需要对目录描述符再显式调用一次 fsync"(man7 fsync(2));大量应用在 rename 前不做这一步、崩溃后新文件零长度或消失的后果,由社区问答与断电实测共同记录(unix.SE: Is it "broken" to replace a file without fsync()?;断电实测见第一节阶段五 Dan Luu《Files are hard》);Python 社区在 bpo-8828 中同样确认 rename 原子但持久性需目录 fsync(Python issue 8828)。这里正是"原子性 ≠ 持久性"的最典型案例:rename 买的是 atomicity,fsync 买的才是 durability。 这套协议并非纸上谈兵——纵轴显示它是 2009 年 O_PONIES 之争被内核拒绝后、经 2015 年 Dan Luu 断电实测与 2018 年 fsyncgate 反复背书的"血写标准"(见第一节阶段五)。
语言库封装:Node 生态的 write-file-atomic 完整实现 temp+fsync+rename(npm/write-file-atomic);Python 的 os.replace 在 POSIX 与 Windows 上均为原子替换但持久性需自行处理(Atomic File Save Patterns、LWN: A way to do atomic writes)。
Windows 原语:Windows 没有 POSIX rename 语义,候选是 MoveFileEx(MOVEFILE_REPLACE_EXISTING) 与 ReplaceFile(后者保留目标 ACL/属性);微软在弃用事务性 NTFS(TxF)后的官方指引就是"写新文件再替换"(Microsoft Learn: TxF 弃用、SO: Is an atomic file rename (with overwrite) possible on Windows?)。2026 年的共识进一步收敛:NTFS 上"持久原子替换"是单次调用 MoveFileEx(MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH),不应把 POSIX 的 fsync-目录模式照搬过去(luth.io: Atomic File Replacement on NTFS Is Not rename + fsync)。
内核与硬件路线(当下时间截面最重要的变化):Linux 6.11(2024)引入块层原子写,向用户态暴露 RWF_ATOMIC 标志,覆盖 SCSI/NVMe(Phoronix: Linux 6.11 Block Atomic Writes);6.13 进一步扩展数据库相关的原子块写支持(LWN: Support for atomic block writes in 6.13);ext4 已在内核文档中正式描述原子(不断裂)块写,XFS 亦已支持,Oracle UEK8 内核已随附(内核文档: ext4 atomic writes)。重要语义:用户态传入 RWF_ATOMIC 而硬件不满足对齐/大小约束时,内核直接报错而非静默降级——这是"宁可失败不可撒谎"的设计取向,与本领域历史上大量隐性降级(见交叉洞察)形成鲜明对照。
替代方案:如果状态是结构化的(多个键、需要事务),正确答案往往是"直接用 SQLite 或 LMDB",而不是手写四步舞——详见 2.7 节。
横轴结论(原子写入):2026 年的原子写入格局呈现明显的双轨制——应用层小文件继续用 rename 舞步(库封装成熟);数据库级大写入开始从"日志 + fsync 舞步"迁移到硬件原子写(RWF_ATOMIC)。跨平台方面,Windows 与 POSIX 语义不可简单互译,这一缝隙由跨平台库填补,也是实际工程中最常见的 bug 来源。
2.6 子领域四:文件锁——并发互斥的三代方案与 Windows 支线
| 方案 | 锁归属 | 崩溃自动释放 | 字节范围 | NFS/分布式 | 主要坑 | 成熟度 |
|---|---|---|---|---|---|---|
| flock(BSD) | 绑定打开文件描述(open file description) | 是(内核锁) | 整文件 | NFS 上与其他锁互操作性依内核版本 | fork 共享 fd 则共享锁 | 数十年 |
| fcntl/lockf(POSIX 记录锁) | 按进程 + 字节范围 | 是 | 是 | 映射到 NLM 协议 | 关闭该文件的任何一个 fd 即释放全部锁(经典事故源) | 数十年 |
| O_EXCL / 锁文件约定 | 文件存在性 | 否(崩溃留陈旧锁) | 无 | 可用于部分分布式 FS | 陈旧锁需超时检测 | 高 |
| Windows LockFileEx | 句柄 + 字节范围 | 是 | 是 | SMB 配合 | 仅字节范围锁,不解决原子替换 | 高 |
| 跨平台库(filelock / portalocker / fasteners / proper-lockfile) | 封装上述原语 | 内核锁路线:是;锁文件路线:需检测 | 部分 | 视路线而定 | 双路线语义不同,混用即坑 | 高 |
分组说明:表中五行按脉络归组——flock 与 fcntl/lockf 同属第一代"内核建议锁";O_EXCL 锁文件为第二代"锁文件约定";跨平台库为第三代"封装层";Windows LockFileEx 不属于这条 Unix 脉络的任何一代,而是与 Unix 建议锁平行的另一套 OS 原语(Windows 没有 flock),下文单独展开。
flock 与 fcntl 的经典分歧(纵轴阶段二与横轴在此重复叙述,正文只述一次):两者都是 advisory 锁(进程可以无视),但语义差异是几十年来 bug 的头号来源——flock 绑定打开文件描述,fork 出的子进程共享同一把锁;fcntl 锁按进程持有,只要关闭指向该文件的任意一个 fd(哪怕是你自己另开的),进程持有的所有 fcntl 锁全部释放(man7: flock(2)、apenwarr: Everything you never wanted to know about file locking、0pointer: On the Brokenness of File Locking)。部分 OS 让 flock 与 fcntl 共享同一锁表,Linux 则基本独立(NFS 上有模拟),跨平台混用会静默失效而非报错(gavv: File locking in Linux、unix.SE: flock vs fcntl over NFS)。纵轴补上历史的最后一笔:2021 年 Linux 5.15 移除强制锁后,建议锁成为唯一正道——40 年演进以"做减法"收尾。
锁文件约定(O_EXCL):最可移植(Windows、部分分布式文件系统都可用),但崩溃后留下陈旧锁是结构性缺陷。Node 生态的 proper-lockfile 用 mtime 心跳 + 超时检测来恢复陈旧锁,是与纯内核锁路线的根本差异(moxystudio/node-proper-lockfile)。
Windows LockFileEx 支线:Windows 没有 flock/fcntl,等价原语是 LockFileEx——锁绑定文件句柄、按字节范围、可选独占(LOCKFILE_EXCLUSIVE_LOCK)与"抢不到立即失败"(LOCKFILE_FAIL_IMMEDIATELY);进程终止或句柄关闭时由操作系统释放锁,崩溃语义与 flock 同级(Microsoft Learn: LockFileEx function)。两个工程要点:① 它只解决并发互斥、不解决原子替换——"先 LockFileEx 锁住、写临时文件、再 MoveFileEx 替换"才是完整配方(见 2.9 节配方一与配方四);② 该函数在 SMB 3.0 上受支持、可用于共享文件场景,但跨主机互斥仍需应用层方案。与 POSIX 侧同理,实际工程不建议手写 LockFileEx,portalocker、filelock 等库已在内部按平台分发到 flock/LockFileEx/锁文件(见下文跨平台库矩阵)。
跨平台库矩阵(2026 年现状):Python 侧——filelock 提供双模式:FileLock(内核锁,崩溃自动释放)与 SoftFileLock(纯锁文件,可能陈旧)(py-filelock 文档);portalocker 包装 flock/lockf/Windows LockFileEx,支持超时与 Redis 后端(wolph/portalocker);fasteners 提供进程锁并天然免陈旧锁(fasteners 文档)。值得注意的是 Python 标准库至今没有内置 IPC 锁文件原语,社区讨论仍在进行(discuss.python.org 帖子)——"锁"这一基础能力仍散落在第三方库里。
横轴结论(文件锁):文件锁只解决并发、不解决崩溃:锁文件的存在性判断在崩溃后不可信,所以现代方案分化为两条明确的路线——内核锁(崩溃自动释放、免维护,但不能跨机器)与锁文件 + 陈旧检测(可跨文件系统语义、但要付心跳/超时的复杂度)。选型第一问是"进程崩了之后,锁还在不在?在就是 bug"。
2.7 子领域五:崩溃恢复——四种恢复哲学的对决
| 方案 | 恢复机制 | 崩溃后需要重放吗 | 持久性语义 | 代价 | 成熟度 |
|---|---|---|---|---|---|
| SQLite rollback journal(默认) | 就地 B 树 + 回滚日志 | 需(回滚未完成事务) | COMMIT 返回即在盘 | 写两次(数据+日志) | 极高 |
| SQLite WAL | 预写日志 + checkpoint | 需(重放 WAL) | WAL 模式默认 synchronous=NORMAL:只防进程崩溃、不防断电;FULL 才防断电 | 顺序写 WAL,读并发好;>100MB 大事务性能差 | 极高 |
| LMDB COW B+树 | 写时复制 + 双根提交,永不覆盖活动页 | 不需要(旧树始终完整,结构性免疫) | 依赖写后 fsync | 写放大(页拷贝) | 高 |
| Redis AOF | 追加日志 + 三档 fsync | 需(重放 AOF) | appendfsync always/everysec(默认)/no,everysec 崩溃约丢 1 秒 | 日志体积与重放时间 | 极高 |
| 文件系统日志(ext4 journal / NTFS) | 元数据(可选数据)日志 | 文件系统自行重放 | 保证文件系统结构一致,不校验数据内容 | 写放大 | 极高 |
分组说明:表中五行归入四种哲学——SQLite 的 rollback journal、SQLite WAL 与 Redis AOF 三行同属"日志重放"(前两者是提交日志的回滚/重放,AOF 是追加重放,档位各不同);LMDB 一行是"结构免疫";文件系统日志一行是"底座兜底";第四种哲学"硬件原子"(RWF_ATOMIC)暂无表格行——它是 2.5 节的新路线,尚在普及初期。
SQLite:持久性档位是最常见的"语义错觉"。WAL 模式(纵轴:2010-07-21 由 3.7.0 引入)把提交从多次 fsync 压缩为一次(先写 WAL、fsync WAL、再择机 checkpoint 回主库)(SQLite 官方 WAL 文档、SQLite atomiccommit 文档)。但 WAL 模式下默认 synchronous=NORMAL,事务在进程崩溃后存活,在断电后可能丢——要防断电必须显式设 synchronous=FULL(avi.im: SQLite commits are not durable under default settings)。SQLite WAL 对超过约 100MB 的大事务性能不佳(SQLite WAL 文档)。这是"以为买了 A 其实只买了 B"的最典型样本:原子性默认满配,持久性默认降档。
LMDB:结构性免恢复。COW 设计永不覆盖正在使用的页,配合双根提交,崩溃后数据库"结构上不可能损坏",无需任何重放/修复过程(Wikipedia: LMDB、lmdb.tech 文档、How LMDB works)。代价是写放大;收益在读路径——Mozilla rkv 设计评审的基准中 LMDB 顺序读最多达 SQLite 的 47 倍(Mozilla rkv design review)。它代表与 WAL 完全相反的哲学:不写日志,用数据结构本身换取恢复的消失。
Redis AOF:持久性是可调价格而非布尔值。appendfsync always("very very slow, very safe")、everysec(默认,崩溃最多丢约 1 秒,后台 fsync 线程滞后时实际可到 1–2 秒)、no(交给 OS)(Redis 官方持久化文档、crash recovery 详解);4.0+ 的混合持久化(RDB 骨架 + AOF 增量)兼顾恢复速度与丢失窗口。Redis 明示即便 always 也不能保证零丢失——真正零丢失需要副本与共识层。
文件系统日志是底座不是答案:ext4 默认 data=ordered 只保证元数据一致,NTFS 同样;它们保证"文件系统结构不烂",不保证"你的数据内容没错"——因此必须与 2.3 节的块级校验互补,而非互替。
横轴结论(崩溃恢复):四种哲学——日志重放(SQLite/Redis)、结构免疫(LMDB)、硬件原子(RWF_ATOMIC)、底座兜底(FS 日志)——没有全能冠军:日志重放通用但默认档位有陷阱,结构免疫优雅但有写放大,硬件原子最快但需要新硬件与新内核。选型的第一问始终是:你要防的是进程崩溃还是断电?两者的价格完全不同。
2.8 选型速查(决策树式)
- 防随机位翻转 → CRC32C(块层)/ XXH3(应用层);防篡改 → SHA-256 或 BLAKE3(大文件)。纯用户态算法,Windows/Linux/macOS 无分支差异。
- 内容去重 + 不可变存储 → Git(源码)/ Bazel CAS(构建)/ restic-Borg(备份)/ IPFS CID(需要算法可演进时)。Windows 分支:Git for Windows、restic、Bazel 均原生支持,无需换型。
- 写一个配置/状态文件 → 同目录 temp + fsync +
os.replace/write-file-atomic;Windows 用单次MoveFileEx(REPLACE_EXISTING|WRITE_THROUGH)——两个分支的完整代码见 2.9 配方一。 - 结构化状态、需要事务 → SQLite(注意 WAL+NORMAL 档位,防断电须显式 FULL,完整配置见 2.9 配方二)或 LMDB(读多写少)。Windows 分支:SQLite 与 LMDB 均官方支持 Windows,无需换型。
- 多进程互斥 → 内核锁优先:POSIX 走 flock(fasteners/portalocker 封装),Windows 走 LockFileEx(portalocker/filelock 封装)——注意 flock 在 2.2 总览矩阵中自标"Unix 系",Windows 上没有 flock,等价物是 LockFileEx;跨 FS/NFS 才用锁文件 + 陈旧检测(proper-lockfile,Node 侧)。完整代码见 2.9 配方四。
- 数据库级大块写入且可控制硬件 → Linux 6.11+ 的 RWF_ATOMIC。Windows 分支:无公开等价 API,此类需求退回"结构化状态交 SQLite"或应用层舞步(见 2.5 节双轨制)。
2.9 落地配方:把决策树变成可复制的最小代码
下面四个配方覆盖大部分日常场景;每个配方都对应 2.1 节"三种语义"中的一条或多条,并给足 Windows 分支——Windows 不是脚注,而是每个配方的一等分支。代码以 Python 为主(标准库可跑),要点对其他语言同样适用。
配方一:小文件原子写入(POSIX 四步舞 + Windows 变体)
# atomic_write.py —— Python 3.8+,POSIX 与 Windows 双分支
import os, sys, tempfile, ctypes
def atomic_write(path: str, data: bytes) -> None:
"""原子替换 path 的内容。
POSIX 侧:四步舞(同目录临时文件 → fsync 文件 → rename → fsync 目录)。
Windows 侧:单次 MoveFileExW(REPLACE_EXISTING | WRITE_THROUGH) 完成持久原子替换。
"""
d = os.path.dirname(os.path.abspath(path))
fd, tmp = tempfile.mkstemp(dir=d, prefix=".tmp-")
try:
with os.fdopen(fd, "wb") as f:
f.write(data)
f.flush()
os.fsync(f.fileno()) # ① 同目录临时文件 ② fsync 文件(持久性)
if sys.platform == "win32":
# ③ NTFS 的"持久原子替换"是单次调用(不要照搬 fsync-目录舞步)
MOVEFILE_REPLACE_EXISTING = 0x1
MOVEFILE_WRITE_THROUGH = 0x8
move = ctypes.WinDLL("kernel32", use_last_error=True).MoveFileExW
move.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
if not move(tmp, path, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH):
raise ctypes.WinError(ctypes.get_last_error())
else:
os.replace(tmp, path) # ③ POSIX:原子替换(原子性)
dfd = os.open(d, os.O_RDONLY) # ④ fsync 目录:让 rename 本身落盘(持久性)
try:
os.fsync(dfd)
finally:
os.close(dfd)
except BaseException:
try:
os.unlink(tmp)
except OSError:
pass
raise语义对照(回到 2.1 节框架):rename/os.replace/MoveFileEx 买的是原子性;fsync 文件、fsync 目录(POSIX)与 MOVEFILE_WRITE_THROUGH(Windows)买的才是持久性——对应 fsync(2) 手册页的目录项要求(2.5 节)。生产环境别手写:Node 直接用 write-file-atomic(内部即 temp+fsync+rename,npm/write-file-atomic);Python 把上面 20 行封成 util;Rust 用 atomicwrites。另外 Windows 上 Python 的 os.replace 只承诺原子替换、没有 WRITE_THROUGH 选项,防断电场景走上面的 ctypes 单调用变体或 ReplaceFile(保留目标 ACL/属性时)。
配方二:SQLite 防断电完整配置(WAL + FULL)
-- 每次打开连接后立即执行:
PRAGMA journal_mode = WAL; -- WAL 模式:读写并发 + 原子提交(写入库文件、持续生效)
PRAGMA synchronous = FULL; -- 关键档位:NORMAL 只防进程崩溃,FULL 才防断电
PRAGMA wal_autocheckpoint = 1000; -- 可选:每 1000 页自动 checkpoint(默认值)
-- 自查:PRAGMA synchronous; 应返回 2(FULL)档位语义矩阵(SQLite 官方文档口径,见 SQLite PRAGMA 文档):
| synchronous | 回滚日志模式 | WAL 模式 |
|---|---|---|
| EXTRA | ACID | ACID |
| FULL | 可能不持久 | ACID |
| NORMAL | 可能不一致 | 可能不持久(事务在进程崩溃后存活、断电后可能回滚) |
| OFF | 不一致 | 不一致 |
三个操作要点:① synchronous 是连接级设置、不随库文件持久化,每个连接都要重设(journal_mode=WAL 则持久);② 只防进程崩溃(SIGKILL)时 NORMAL 即可,防断电/OS 崩溃必须 FULL;③ 档位受编译选项与发行版影响(macOS 系统自带 SQLite 默认档位有差异),务必显式设置后用 PRAGMA synchronous; 自查(avi.im: SQLite commits are not durable under default settings)。Python 侧两行接入:
import sqlite3
con = sqlite3.connect("app.db")
con.execute("PRAGMA journal_mode = WAL")
con.execute("PRAGMA synchronous = FULL") # 防断电;只防进程崩溃可省配方三:校验和三问(存哪 / 何时验 / 坏了怎么办)
- 存哪:校验和与数据的存放关系决定它能抓住哪类损坏——存在数据旁边(
foo.txt.sha256)只防传输与下载损坏;存在父块/对象头里(ZFS 父块指针、Git 对象链)才能防错址读写与静默损坏;存在独立清单/账本里(备份仓库目录、manifest.sha256)才能做全量巡检。原则:与数据分开存放,最好跨介质或跨副本(端到端论证的应用)。 - 何时验:三个时机缺一不可——写入时算(生成即留档,代价最低);读取时验(关键路径按需);后台巡检(scrub /
borg check --verify-data/ 定期比对清单)。只算不验等于没做。
# 最小巡检配方(POSIX;清单与数据分开存放)
find data/ -type f -exec sha256sum {} + > manifests/data.sha256
# 定期巡检(cron/计划任务),只打印损坏行
sha256sum -c manifests/data.sha256 | grep -v ': OK$'
# Windows 侧单文件校验可用 PowerShell Get-FileHash 或 certutil -hashfile <文件> SHA256- 坏了怎么办:预案先于事故——① 有多副本(RAID-Z/镜像/异地备份)先从副本恢复;② 单副本则先确认损坏范围、隔离坏对象、从源头重拉;③ 把损坏事件写进监控(bit rot 常成簇出现,一次损坏往往是下一次的预兆)。没有预案的校验和只是"更优雅的报错"。
配方四:多进程互斥(POSIX flock 与 Windows LockFileEx)
# POSIX:内核锁,进程死自动释放,无需陈旧锁清理
import fcntl, os
lock_fd = os.open("/var/run/job.lock", os.O_CREAT | os.O_RDWR)
fcntl.flock(lock_fd, fcntl.LOCK_EX) # 阻塞等待;LOCK_NB 则抢不到立即抛 BlockingIOError
try:
... # 临界区
finally:
fcntl.flock(lock_fd, fcntl.LOCK_UN)
os.close(lock_fd)# 跨平台(含 Windows):推荐走库,由库按平台分发到 flock / LockFileEx / 锁文件
import portalocker
with portalocker.Lock("job.lock", timeout=10) as fh:
... # 临界区;退出上下文即释放(异常时同样释放)Windows 原生语义(库内部做的事):LockFileEx 绑定句柄、按字节范围、独占/共享可选,进程终止或句柄关闭时由 OS 释放(见 2.6 节 Windows 支线)——与 flock 的"崩溃自动释放"同级。portalocker.Lock 在等待超时后获取锁、退出上下文即释放(portalocker 文档,用法已对照官方示例核实)。选型判断题仍是那句:进程崩了之后,锁还在不在?内核锁路线答"不在(正确)",锁文件路线答"还在(陈旧锁,需心跳/超时检测)"(对应 2.6 节结论)。
三、交叉洞察:两轴结合说明了什么
3.1 六条合并去重后的共识
- 故障模型下移、防御上移,端到端论证被三个十年反复兑现——且横轴证据表明它至今仍未"毕业"。 纵轴的主线一(RAID 被打穿 → ZFS 端到端校验 → S3 默认 CRC)在横轴上得到当代注脚:Meta 在数十万机器规模上发现"静默出错的 CPU"——每数千颗处理器中即约有一颗存在不触发任何报警的计算错误(Meta engineering blog, 2021,相关论文 *Cores that don't count*, HotOS '21, arXiv:2102.11245);Google 2009 年的 DRAM 大规模田野研究显示内存错误远高于预期且以硬错误为主(Schroeder et al., 2009);微软研究院 2012 年的《Cosmic Rays Don't Strike Twice》基于近 300 TB-年的生产内存数据进一步指认:相当大比例的现场错误是硬错误而非偶发宇宙射线(ASPLOS 2012,见参考来源);而横轴还指出"没有 ECC 内存时连 ZFS 也无法闭环"。结论:即使有 ECC、有 ZFS,关键数据仍应做应用层端到端校验(内容寻址或显式 checksum),因为每一层都只覆盖自己之后、下一层之前的那段路径。 两轴交叉的价值正在于此:纵轴证明"信任中间层"每次都输,横轴证明中间层今天仍在静默出错。
- 三种语义分开买,且默认档位普遍降档——这不是理论风险,而是被纵轴事故史反复验证的现实。 横轴的框架(rename 给 atomicity 不给 durability;WAL+NORMAL 给 atomicity 不给 power-loss durability;CRC32C 给 integrity 不给对抗性)与纵轴的事故编年严丝合缝:2009 年 O_PONIES 之争是"应用想买 durability、内核拒绝代买"的分水岭;2015 年 Dan Luu 用断电实测证明跳过 fsync 的 rename 在真实文件系统上丢数据;2018 年 fsyncgate 曝出内核把 fsync 错误"上报一次后丢弃",PostgreSQL"错误使用 fsync 达 20 年"。数据完整性工程的一半工作量,是把 Integrity/Atomicity/Durability 三个词从"感觉安全"变成逐条指认由哪个机制、在什么档位、覆盖哪类故障。
- 哈希从检错到身份是 70 年里最大的一次范式迁移,而横轴显示这次迁移还在升级。 纵轴主线三(CRC 检错 → MD5/SHA-1 认证并两次退位 → SHA-2/BLAKE3 时代哈希成为地址与账本)与横轴的内容寻址格局拼成完整图景:Git 把算法写死在仓库里(升级即迁移,LWN 记录的转换困境),IPFS CID 用 multihash 让算法自描述、可逐标识符演进——"身份即证明"的下一步是"身份可换证明算法"。同样的自描述化也出现在账本侧:RFC 6962 日志 2025 年起退役、转向算法可演进的 Merkle Tree Certificates 草案。
- 两轴共同指向同一个收敛方向:更快、更自描述、更少隐式假设。 横轴洞察(校验和从"快与强二选一"走向 BLAKE3"又快又强";内容寻址从算法写死走向 CID 自描述;原子写入走向 RWF_ATOMIC"硬件保证 + 不满足即报错";备份从裸仓库走向认证加密仓库)在纵轴上都能找到时间锚点:2019–2025 年这四条线几乎同步完成了一次"显式化"升级——校验和侧 S3 把默认校验做成零成本(2022)、OpenZFS 2.3 直接采用 BLAKE3(2025);身份与协议侧 RFC 9530 把摘要算法显式写进标准字段(2024);原子写入侧 Linux 6.11 的 RWF_ATOMIC 宁报错不撒谎(2024);备份侧的认证加密仓库(restic/Borg)在此前十年已定型为默认(见第一节阶段五)。当一层防线无法被显式指认时,它正在被移除;当一层防线无法被绕过时,它正在变成默认。
- 五个子领域在实际系统里是咬合的,不存在单点最优。 横轴的咬合链(内容寻址的写入需要原子替换兜底半成品对象;引用计数的并发修改需要文件锁;锁的崩溃语义决定是否需要陈旧检测;崩溃恢复机制决定持久性档位;机制的终点都需要校验和闭环验证)与纵轴的样板互相印证:SQLite 的五态锁 + WAL、Git 的 lockfile + 对象哈希 + fsync 协议,都是"五件套各自就位"的整体设计——页级校验和则是 PostgreSQL 9.3(2013 年)起的能力(见第一节阶段四)。评估任何一个"数据完整性方案"时,应画出它在这五个位置各取了什么、什么没取。
- 跨平台语义差是持续性成本中心,答案是收敛到少数经过验证的库。 flock/fcntl 语义分歧(关 fd 即放锁)、Windows 单调用
MoveFileExvs POSIX 四步舞、LockFileEx 的字节范围模型——每一处都产生真实事故与专门的库。2026 年的实践共识:这类底层语义差异应收敛到 write-file-atomic、fasteners、portalocker、proper-lockfile 等少数经过验证的库,而不是在每个项目里重新发明;纵轴的教训(fsyncgate 之前 PostgreSQL 也自认为用法正确)说明"自己写"的隐含成本远高于引库。
3.2 对用户的判断与建议
第一,把"三种语义清单"当作任何写路径设计的必答题。 上线前逐条写下:这份数据防谁(随机错/篡改)→ 由谁检测(CRC32C/XXH3 还是 SHA-256/BLAKE3);读者会不会看见半成品 → 谁保证原子性(rename/RWF_ATOMIC/WAL);断电后丢多少 → 谁保证持久性、在什么档位(fsync 协议 / synchronous=FULL / AOF 档位)。回答不了任何一条,就是下一个 fsyncgate。
第二,按 2.8 节决策树选型,不要在体系外发明新原语。 防随机错 CRC32C/XXH3、防篡改 SHA-256/BLAKE3 不可互替;小文件替换直接用语言库;结构化状态直接上 SQLite(检查 WAL 档位)或 LMDB;多进程互斥优先内核锁(POSIX 走 flock/portalocker,Windows 走 LockFileEx 语义的库封装,见 2.9 配方四)。特别注意 SQLite 的默认档位陷阱:WAL + NORMAL 只防进程崩溃,防断电须显式 synchronous=FULL。
第三,端到端校验不可省,且要覆盖"存储层校验看不见的路径"。 即使已用 ZFS/Btrfs 或云盘,关键数据仍应保留应用层校验(内容寻址或显式 checksum):Meta 的静默 CPU、Google 的 DRAM 研究、ZFS 与内存之间的盲区都说明中间层会漏。S3 时代应直接用上 CRC32C/SHA-256 请求级校验(2022 年起已零成本默认)。
第四,留意 2026–2030 的换代窗口,新项目不再采用进入退役周期的算法与语义。 SHA-1 已被 NIST 判 2030 年底退役;Git 新仓库应评估 SHA-256 对象格式(存量转换生态未完成,源码仓库迁移需规划);强制文件锁语义已在 Linux 5.15 移除,任何依赖 -o mand 的老代码都是隐患。
第五,硬件原子写是值得观察但不必抢跑的方向。 RWF_ATOMIC(Linux 6.11+,ext4/XFS,需 NVMe/SCSI 支持)语义干净(不满足即报错),适合数据库级大块写入;应用层小文件在 2026 年的最佳实践仍是"库封装的四步舞",等硬件普及与文件系统成熟度跟上再迁移。
附录一:综合校准记录(两章矛盾与重复的处理)
- BLAKE3 发布年份:横轴表格作"2019 发布"(两处),纵轴给出带来源的 2020-01-09(Wikipedia: BLAKE)、BLAKE3 规格书)。采纵轴 2020-01-09;横轴"2019"应为开发启动/规范筹备期,正文与总览矩阵均已统一为 2020。
- SHA-1 碰撞的佐证层级:横轴 2.2 节标注"SHA-1 已于 2017 年被 Google/CWI 公开构造出实际碰撞,此为模型既有知识补充,本轮未单独检索核实";纵轴阶段五有一手来源(shattered.io、CWI 新闻稿、NIST 回应)。采纵轴带来源版本,横轴处的"既有知识"标注不再保留。
- BLAKE3 相对 SHA-256 的速度倍数:横轴引官方仓库口径 15–27×(裸哈希、多核 AVX-512),纵轴引 OpenZFS 2.3 集成口径约 3×。两者测量条件不同(裸哈希并行 vs 文件系统集成开销),正文并列两口径并注明差异,不再当作矛盾。
- Git SHA-1/SHA-256 现状的两种表述:纵轴(2.29 实验格式、社区计划 3.0 默认)与横轴("算法固定于仓库"、转换生态未完成)并非矛盾而是互补,合并为一句:SHA-256 可选格式 2020 年引入、计划设为默认,但存量迁移生态未完成——并保留两侧来源(Phoronix|LWN 898522)。
- SQLite WAL 的双重叙述:纵轴从时间轴讲(3.7.0 于 2010-07-21 引入),横轴从档位语义讲(NORMAL 只防进程崩溃、FULL 才防断电)。合并为一段:时间锚点 + 档位语义同段呈现,来源取并集(SQLite WAL 文档|avi.im)。
重复合并清单:flock/fcntl 语义分歧与三大锁史文献(man7/apenwarr/0pointer)两章均详述,正文只在 2.6 节详述一次并在纵轴阶段二保留时间轴;FAST '10 ZFS 论文两章均引,正文在历史视角(第一节阶段四)与对比视角(2.3 节存储层)各实质引用一次,参考来源合并去重为一个条目;SQLite WAL/atomiccommit 文档、BLAKE3 规格/仓库、Git SHA-256 来源均已在参考来源合并去重。
附录二:审读修订记录(2026-11-04 定稿)
初稿收到 8 条独立审读意见,逐条修订如下(行号以初稿为准):
- 引用错配(原 L181,硬伤):经核实,rename(2) 手册页并无"零长度或消失"警告,mount(2) 归属错误。改为引 fsync(2) 手册页原文("调用 fsync() 并不保证目录项落盘,需对目录描述符显式 fsync",man7 已核实),unix.SE 保留为社区问答来源,断电实测后果挂回 Dan Luu《Files are hard》。
- 计数错误(原 L252):"五条线"改"四条线",四条线逐一挂时间锚点(S3 2022、OpenZFS 2.3 2025、RFC 9530 2024、RWF_ATOMIC 2024;备份认证加密注明定型于 2010 年代中后期)。
- 术语与归属(原 L83/L254):五态锁在首现处一句话定义(UNLOCKED→SHARED→RESERVED→PENDING→EXCLUSIVE,引 SQLite lockingv3 文档,已核实);L254 改写为"页级校验和是 PostgreSQL 9.3(2013 年)起的能力"。
- 论断不可读(原 L161):删去"SHA-256 对象可引用任意对象"半句,按 LWN 898522 实际内容改写(两格式仓库无法互相 push、托管平台未支持、40 字符假设、2.31 后无实质进展),均已对照 LWN 原文核实。
- 标题数字与表格行数(原 2.3/2.4/2.6/2.7):2.3 标题改"六条路线"、2.4 改"六种实现",各表后加分组说明;2.6 标题改"三代方案与 Windows 支线"并补 LockFileEx 正文一段(引 Microsoft Learn 已核实);2.7 保留"四种哲学"并加归组说明(两行 SQLite + AOF 同属日志重放,硬件原子无表格行)。
- 口径与量纲(原 L126/L205/L128/L165):proper-lockfile 统一为"Node 生态";LMDB"Monkey"删除,改列可核实用户(Postfix、PowerDNS、Monero,对照 Wikipedia 应用清单);"约多省 10%"删除——所引 monovm 对比文章中并无此数字,改按该文实际口径"Borg 存储效率口碑更强(去重 + 可调压缩),restic zstd 后差距缩小"。
- 附录自述与来源对齐(原 L280/L346/L20):FAST '10 论文改口径为"历史视角与对比视角各引一次";孤儿条目《Cosmic Rays Don't Strike Twice》在 3.1 节补正文引用,并补 ASPLOS 2012 出处与出版方页面直链(已核实);Ritter《The Great CRC Mystery》补作者站点链接(已核实为 Dr. Dobb's Journal 11(2),1986 年 2 月)并入参考来源。
- 落地配方与 Windows 分支(原 2.8 及全文):新增 2.9 节四个配方(原子写入双平台含 ctypes 的 MoveFileExW 变体、SQLite WAL+FULL 完整配置与档位矩阵、校验和三问含巡检脚本、多进程互斥双平台);决策树逐条补 Windows 分支(flock 在 Windows 的等价物为 LockFileEx、RWF_ATOMIC 无 Windows 等价等)。配方中的 API 语义(MoveFileEx 旗标 0x1/0x8、LockFileEx 释放时机、portalocker.Lock 用法、SQLite 档位矩阵)均经本次定稿逐条在线核实。
四、参考来源(两章合并去重)
奠基与编码理论
- Hamming 1950 论文 PDF:https://zoo.cs.yale.edu/classes/cs323/doc/Hamming.pdf ;Wiley DOI:https://onlinelibrary.wiley.com/doi/10.1002/j.1538-7305.1950.tb00463.x ;Internet Archive 扫描件:https://archive.org/details/bstj29-2-147
- Merkle tree - Wikipedia:https://en.wikipedia.org/wiki/Merkle_tree
- RAID 论文 PDF(CMU):https://www.cs.cmu.edu/~garth/RAIDpaper/Patterson88.pdf ;ACM DL:https://dl.acm.org/doi/10.1145/50202.50214 ;CHM 评论:https://www.computerhistory.org/storageengine/u-c-berkeley-paper-catalyses-interest-in-raid
- End-to-End Arguments(MIT 原文 PDF):https://web.mit.edu/saltzer/www/publications/endtoend/endtoend.pdf ;ACM DL:https://dl.acm.org/doi/10.1145/357401.357402
- Ritter, T.《The Great CRC Mystery》(Dr. Dobb's Journal 11(2):26–34, 76–83,1986-02):http://www.ciphersbyritter.com/ARTS/CRCMYST.HTM
文件系统与崩溃恢复(纵轴史料)
- LFS 论文 PDF(Stanford):https://web.stanford.edu/~ouster/cgi-bin/papers/lfs.pdf ;ACM DL:https://dl.acm.org/doi/10.1145/146941.146943
- ARIES 课程材料(MIT 6.5830):https://dsg.csail.mit.edu/6.5830/lectures/recovery.php ;DBtech 讲义 PDF:https://homepages.cwi.nl/~manegold/teaching/DBtech/slides/Aries-4.pdf
- Tweedie 日志论文 PDF:http://www.cs.columbia.edu/~junfeng/12sp-w4118/lectures/journal-design.pdf ;Ext3 - Wikipedia:https://en.wikipedia.org/wiki/Ext3
- Soft Updates(USENIX 1999):https://www.usenix.org/conference/1999-usenix-annual-technical-conference/soft-updates-technique-eliminating-most ;TOCS 论文 PDF:http://users.ece.cmu.edu/~ganger/papers/softupdates.pdf
- Btrfs LKML 原始公告:https://lkml.org/lkml/2007/6/12/242 ;LWN:https://lwn.net/Articles/358940 ;Linux Foundation 访谈:https://www.linuxfoundation.org/blog/blog/a-conversation-with-chris-mason-on-btrfs
- FAST '10:End-to-end Data Integrity for File Systems (ZFS Case Study):https://research.cs.wisc.edu/wind/Publications/zfs-corruption-fast10.pdf
- ZFS 演讲 PDF(The Last Word in File Systems):https://www.prsl.ch/twiki/pub/Betriebssysteme/SkriptVorlesung/zfs_last.pdf ;Cantrill 博客:https://bcantrill.dtrace.org/2005/11/16/welcome-to-zfs
- StarWind: Btrfs vs ZFS:https://www.starwindsoftware.com/blog/btrfs-vs-zfs ;Reddit r/zfs 无 ECC 讨论:https://www.reddit.com/r/zfs/comments/13jszy6/data_corruption_in_case_of_zfs_without_ecc
增量同步与内容寻址
- rsync 技术报告:https://www.samba.org/rsync/tech_report ;Tridgell 博士论文:https://www.samba.org/~tridge/phd_thesis.pdf ;Wikipedia: Rsync:https://en.wikipedia.org/wiki/Rsync
- Git - Wikipedia:https://en.wikipedia.org/wiki/Git ;The New Stack 20 周年回顾:https://thenewstack.io/linus-torvalds-reflects-on-20-years-of-git
- Nix 博士论文 PDF:https://edolstra.github.io/pubs/phd-thesis.pdf ;NixOS Research:https://nixos.org/research
- GFS - Wikipedia:https://en.wikipedia.org/wiki/Google_File_System ;BitTorrent - Wikipedia:https://en.wikipedia.org/wiki/BitTorrent
- IPFS 白皮书:https://arxiv.org/abs/1407.3561 ;IPFS 官方文档 Content Addressing:https://docs.ipfs.tech/concepts/content-addressing ;CID 规范:https://github.com/multiformats/cid ;Filebase CID 拆解:https://filebase.com/blog/understanding-the-components-of-an-ipfs-cid
- LWN: Whatever happened to SHA-256 support in Git?:https://lwn.net/Articles/898522 ;Phoronix Git 2.29 SHA-256:https://www.phoronix.com/news/Git-2.29-With-SHA-256 ;GitHub Blog Git 2.29:https://github.blog/open-source/git/git-2-29-released
- Bazel 远程缓存文档:https://bazel.build/remote/caching ;EngFlow: The Many Caches of Bazel:https://blog.engflow.com/2024/05/13/the-many-caches-of-bazel ;bazel-remote:https://github.com/buchgr/bazel-remote
- restic vs Borg:https://monovm.com/blog/restic-vs-borg ;https://www.matthewswong.com/en/blog/restic-vs-borg-encrypted-backups ;Borg check 文档:https://borgbackup.readthedocs.io/en/stable/usage/check.html ;restic 论坛 CDC 去重安全性:https://forum.restic.net/t/how-safe-is-deduplication-content-defined-chunking/5867
校验和与哈希算法
- xxHash 官方基准:https://xxhash.com/doc/v0.8.2/index.html ;xxHash 仓库基准讨论 #660:https://github.com/Cyan4973/xxHash/issues/660
- BLAKE3 官方仓库:https://github.com/BLAKE3-team/BLAKE3 ;BLAKE3 规格书 PDF:https://raw.githubusercontent.com/BLAKE3-team/BLAKE3-specs/master/blake3.pdf ;Wikipedia: BLAKE:https://en.wikipedia.org/wiki/BLAKE_(hash_function)
- MojoAuth: xxHash vs BLAKE3:https://mojoauth.com/security-guides/xxhash-vs-blake3 ;CodeSector 校验和格式指南:https://codesector.com/how-to/choose-checksum-file-format
- shattered.io(SHAttered):https://shattered.io ;CWI 新闻稿:https://www.cwi.nl/en/news/cwi-and-google-announce-first-collision-for-industry-security-standard-sha-1 ;NIST 2017 回应:https://csrc.nist.gov/news/2017/research-results-on-sha-1-collisions ;Wang & Yu EUROCRYPT 2005:https://link.springer.com/chapter/10.1007/11426639_2
- NIST SHA-1 退役新闻:https://www.nist.gov/news-events/news/2022/12/nist-retires-sha-1-cryptographic-algorithm ;NIST 哈希政策:https://csrc.nist.gov/projects/hash-functions/nist-policy-on-hash-functions
- RFC 9530 Digest Fields:https://www.rfc-editor.org/info/rfc9530 ;Lucas Pardue 解读:https://lucaspardue.com/2026/08/08/http-integrity ;RFC 6962:https://www.rfc-editor.org/info/rfc6962 ;Certificate Transparency - Wikipedia:https://en.wikipedia.org/wiki/Certificate_Transparency
- Let's Encrypt RFC 6962 EOL 公告:https://letsencrypt.org/2025/08/14/rfc-6962-logs-eol ;Merkle Tree Certificates 草案:https://www.ietf.org/archive/id/draft-davidben-tls-merkle-tree-certs-09.html
- AWS S3 校验博客:https://aws.amazon.com/blogs/aws/new-additional-checksum-algorithms-for-amazon-s3 ;S3 用户指南:https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html ;第三方分析:https://hidekazu-konishi.com/entry/amazon_s3_default_checksums_and_data_integrity.html
- OpenZFS 2.3(Phoronix):https://www.phoronix.com/news/OpenZFS-2.3-Released
原子写入与持久化协议
- man7 fsync(2)(目录项需显式 fsync 的原文出处):https://man7.org/linux/man-pages/man2/fsync.2.html
- Microsoft Learn MoveFileExA/MoveFileExW(winbase.h,REPLACE_EXISTING=0x1、WRITE_THROUGH=0x8):https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexa
- Dan Luu《Files are hard》:https://danluu.com/file-consistency ;《Filesystem error handling》:https://danluu.com/filesystem-errors/ ;fsyncgate 邮件存档:https://danluu.com/fsyncgate
- LWN O_PONIES:https://lwn.net/Articles/351422 ;LevelDB issue #195:https://github.com/google/leveldb/issues/195
- PG Wiki Fsync Errors:https://wiki.postgresql.org/wiki/Fsync_Errors
- KernelNewbies Linux 3.11:https://kernelnewbies.org/Linux_3.11 ;LWN RENAME_EXCHANGE:https://lwn.net/Articles/569134 ;man7 rename(2):https://man7.org/linux/man-pages/man2/rename.2.html
- unix.SE 不 fsync 就 rename:https://unix.stackexchange.com/questions/297632/is-it-broken-to-replace-an-existing-file-without-fsync ;Python issue 8828:https://bugs.python.org/issue8828 ;LWN atomic writes:https://lwn.net/Articles/789600 ;Atomic File Save Patterns:https://0xkiire.com/atomic-file-save-patterns
- npm/write-file-atomic:https://github.com/npm/write-file-atomic
- Microsoft Learn TxF 弃用:https://learn.microsoft.com/en-us/windows/win32/fileio/deprecation-of-txf ;SO Windows 原子 rename:https://stackoverflow.com/questions/167414/is-an-atomic-file-rename-with-overwrite-possible-on-windows ;luth.io NTFS 原子替换(2026-08):https://luth.io/blog/2026/08/ntfs-atomic-file-replacement-not-rename-fsync
- Phoronix Linux 6.11 Block Atomic Writes:https://www.phoronix.com/news/Linux-6.11-Block-Atomic-Writes ;LWN 6.13 原子块写:https://lwn.net/Articles/1009298 ;内核文档 ext4 atomic writes:https://docs.kernel.org/filesystems/ext4/atomic_writes.html
文件锁
- man7 flock(2):https://man7.org/linux/man-pages/man2/flock.2.html ;apenwarr 锁史:https://apenwarr.ca/log/20101213-everything-you-never-wanted-to-know-about-file-locking ;0pointer.de:https://0pointer.de/blog/projects/locking.html ;gavv File locking in Linux:https://gavv.net/articles/file-locks ;unix.SE flock vs fcntl over NFS:https://unix.stackexchange.com/questions/1777/flock2-versus-fcntl2-over-a-nfs
- Microsoft Learn LockFileEx function(fileapi.h):https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex
- KernelNewbies Linux 5.15:https://kernelnewbies.org/Linux_5.15 ;内核 5.14 changelog:https://cdn.kernel.org/pub/linux/kernel/v5.x/ChangeLog-5.14
- py-filelock:https://py-filelock.readthedocs.io ;wolph/portalocker:https://github.com/wolph/portalocker ;fasteners:https://fasteners.readthedocs.io ;moxystudio/node-proper-lockfile:https://github.com/moxystudio/node-proper-lockfile ;discuss.python.org 标准库锁讨论:https://discuss.python.org/t/lockfile-implementation-in-the-standard-library-ipc-lockfile-not-packaging/44896
崩溃恢复与嵌入式存储
- SQLite WAL 文档:https://www.sqlite.org/wal.html ;SQLite 3.7.0 changelog:https://www.sqlite.org/releaselog/3_7_0.html ;SQLite Atomic Commit:https://sqlite.org/atomiccommit.html ;avi.im SQLite 默认档位(2025):https://avi.im/blag/2025/sqlite-fsync
- SQLite File Locking 文档(五态锁定义):https://www.sqlite.org/lockingv3.html ;SQLite PRAGMA 文档(synchronous 档位矩阵):https://www.sqlite.org/pragma.html
- LMDB - Wikipedia(应用清单:Postfix、PowerDNS、Monero 等):https://en.wikipedia.org/wiki/Lightning_Memory-Mapped_Database ;lmdb.tech 文档:http://www.lmdb.tech/doc/lmdb0.9 ;How LMDB works:https://xgwang.me/posts/how-lmdb-works ;Mozilla rkv design review:https://mozilla.github.io/firefox-browser-architecture/text/0015-rkv.html
- Redis 持久化文档:https://redis.io/docs/latest/operate/oss_and_stack/management/persistence ;Redis crash recovery 详解:https://engineeringatscale.substack.com/p/redis-persistence-aof-rdb-crash-recovery
数据库与静默损坏研究
- PostgreSQL 9.3 checksums(EndPoint):https://www.endpointdev.com/blog/2013/10/downstream-implications-of-data-page ;Paquier 笔记:https://paquier.xyz/postgresql-2/postgres-9-4-feature-highlight-data-checksum-switch-as-a-guc-parameter
- PostgreSQL 18 公告:https://www.postgresql.org/about/news/postgresql-18-released-3142 ;pganalyze AIO 分析:https://pganalyze.com/blog/postgres-18-async-io ;depesz PG19 在线 checksum:https://www.depesz.com/2026/04/15/waiting-for-postgresql-19-online-enabling-and-disabling-of-data-checksums
- Meta 静默数据损坏(2021):https://engineering.fb.com/2021/02/23/data-infrastructure/silent-data-corruption ;*Cores that don't count*(HotOS '21):arXiv:2102.11245 ;Schroeder et al., *DRAM Errors in the Wild*(2009,经横轴检索摘要确认存在,属经典文献);Microsoft Research, *Cosmic Rays Don't Strike Twice*(ASPLOS 2012,3.1 节正文已引):https://www.microsoft.com/en-us/research/publication/cosmic-rays-dont-strike-twice/
块级完整性
- SCSI SBC-3 标准草案(T10 DIF/PI):http://www.13thmonkey.org/documentation/SCSI/sbc3r25.pdf
*报告生成:2026-11-04,综合报告(纵轴 × 横轴)。全部事实与数字来自两份分轴章节文件(parts/2026-11-04-数据完整性工程-校验和-内容寻址-原子写入-vertical.md 与 parts/2026-11-04-数据完整性工程-校验和-内容寻址-原子写入-文件锁-崩溃恢复-horizontal.md)及其标注来源;两稿各自标注的"背景知识"处沿用原标注;矛盾与重复的处理见附录一校准记录。本文件为最终稿,已按独立审读意见完成 8 条修订(逐条见附录二),初稿存于 drafts/ 未改动。*