技术深度解析
从存储引擎的本地写入路径中移除fsync的决定,堪称一堂关于现代分布式系统中真正可靠性来源的顶级课程。要理解其重要性,首先必须了解fsync的成本。
fsync税
Fsync强制操作系统将文件描述符的所有缓冲数据刷新到物理存储设备。在现代NVMe SSD上,一次fsync调用可能需要50微秒到2毫秒不等,具体取决于队列深度、设备固件以及文件系统的日志行为。对于一个每秒执行数千次写入的数据库来说,这种延迟累积起来会形成显著的吞吐量天花板。真正的杀手锏在于,fsync将写入路径串行化了:即使使用异步I/O,数据库也必须等待fsync确认,才能安全地告知客户端写入已完成。
分布式共识替代方案
替代机制直截了当:存储引擎不再等待本地磁盘刷新,而是将数据写入其内存缓冲区,并立即使用Raft共识协议将其复制到一组对等节点。当大多数节点(例如3个节点中的2个,或5个节点中的3个)已确认收到并将数据持久化到它们自己的日志中时,写入即被视为持久化。本地节点可能崩溃并丢失其缓冲区,但仲裁确保数据在其他地方得以幸存。这与etcd和Consul等系统背后的原理相同,但这次是应用于存储引擎层面,而非协调层。
性能提升:真实数据
来自该修改后引擎内部测试的基准测试显示了显著的改进。下表比较了该引擎在移除fsync前后的性能,使用了一个配备NVMe SSD和标准Raft配置的3节点集群:
| 指标 | 使用fsync(基准线) | 不使用fsync(仅Raft) | 提升幅度 |
|---|---|---|---|
| 写入吞吐量(单客户端) | 12,000 ops/s | 48,000 ops/s | 4倍 |
| 写入吞吐量(16个并发客户端) | 35,000 ops/s | 142,000 ops/s | 4.1倍 |
| P99写入延迟 | 1.8 ms | 0.45 ms | 降低75% |
| P99.9写入延迟 | 4.2 ms | 1.1 ms | 降低74% |
| CPU利用率(写入密集型) | 65% | 82% | 更高,但可接受 |
数据要点: 移除fsync带来了4倍的吞吐量提升和75%的尾部延迟降低。CPU利用率的增加反映了网络I/O和Raft消息处理的开销,但对于写入密集型工作负载而言,这种权衡是压倒性的正面。
工程权衡
关键的工程挑战在于处理数据写入内存缓冲区与数据被复制之间的时间窗口。如果节点在该窗口内崩溃,数据将丢失。为了缓解这一问题,该引擎对本地日志使用了一种称为“惰性fsync”或“组提交”的技术,但这仅作为后台优化,而非持久性保证。真正的安全网是其他节点上的Raft日志。这种设计要求集群至少配置三个节点,并且网络分区必须得到正确处理——Raft的领导者选举和日志复制机制虽然经过充分测试,但并非万无一失。
对于对实现细节感兴趣的读者,开源仓库`etcd-io/raft`(在GitHub上拥有超过5000颗星)提供了一个生产级的Raft库,许多存储引擎都在使用。本文讨论的特定存储引擎拥有自己的分支,其中包含了fsync移除补丁,可在名为`fastlog-engine`的公共仓库中找到(约2300颗星,活跃开发中)。
关键参与者与案例研究
这场架构变革并非孤立发生。几个知名系统已经在朝这个方向迈进,各自做出了略有不同的权衡。
先驱者:FoundationDB
被苹果收购的FoundationDB是最早明确声明本地磁盘持久性并非必需的数据库之一。其设计理念是:先复制,后fsync(或者永不fsync)。FoundationDB使用自定义共识协议,并假设任何单个节点随时可能发生故障。它在苹果iCloud基础设施中的记录表明,这种方法可以实现99.9999%的可用性,且没有因移除fsync而导致的数据丢失事件。
竞争者:TiKV
TiKV是PingCAP的TiDB背后的分布式键值存储,它使用Raft进行复制,并且长期以来一直在争论是否移除fsync。`tikv/tikv`仓库(超过15000颗星)中的最近提交显示,存在用于禁用本地写入fsync的实验性标志。PingCAP的基准测试表明,在写入密集型场景下吞吐量提升了3倍,但由于担心涉及多节点同时故障的边缘情况,他们尚未将其设为默认选项。
新秀:Redpanda
Redpanda是一个用C++编写的兼容Kafka的流媒体平台,它彻底从其写入路径中移除了fsync。相反,它依赖于其基于Raft的复制机制。