Hacker News 中文摘要

RSS订阅

Linux 数据库中异步 I/O 的实现 -- Async I/O on Linux in databases

文章摘要

文章探讨了在Linux系统上使用异步I/O(iouring)提升数据库性能的方法。作者通过对比传统同步I/O(如fsync)和iouring的异步特性,指出后者能够避免线程池和复杂状态机,显著提高I/O操作的效率。作者在开发Kevo和Klay数据库时,尝试利用io_uring优化磁盘操作的可靠性和速度,旨在实现更高效的持久化存储。

文章总结

文章主要内容重述

标题:Linux 上的异步 I/O 与持久性

来源:https://blog.canoozie.net/async-i-o-on-linux-and-durability/

发布时间:2025年7月18日

主要内容

作者在开发一个复杂的多模型数据库时,尝试在简单的键值数据库中测试一种新的异步I/O方法。最初,作者使用了一个内存中的哈希表和一个简单的仅追加日志来实现持久性,并通过每次写入后调用fsync()来确保数据的持久性。虽然这种方法有效,但性能并不理想。

在探索更高效的解决方案时,作者开始研究Linux的io_uring技术。io_uring通过一对环形缓冲区(提交队列和完成队列)实现了真正的异步I/O,允许应用程序提交多个操作并收集结果,而不需要为每个操作单独调用系统调用。作者通过将同步的WAL(Write-Ahead Log)写入替换为异步写入,显著提高了吞吐量。

然而,异步I/O在数据库环境中带来了持久性问题。客户端在收到成功响应时,期望数据在系统崩溃后仍然存在,但异步I/O可能导致数据仍在内核缓冲区中,尚未写入稳定存储。为了解决这个问题,作者设计了一种双WAL系统:

  1. 意图WAL:记录计划执行的操作。
  2. 完成WAL:记录这些操作的成功完成。

在恢复过程中,系统只应用同时具有意图记录和完成记录的操作,确保了一致性,同时允许更高的吞吐量。

作者使用Zig语言实现了这个双WAL系统,并通过io_uring的批处理能力进一步优化了性能。每个完成条目包括校验和和对相应意图条目的引用,确保数据完整性。恢复算法变得更加复杂但更健壮,能够优雅地处理部分失败情况。

最终,基准测试显示,与原始的同步实现相比,事务吞吐量提高了10倍,系统现在能够随着CPU核心数量的增加而扩展,而不是被磁盘I/O串行化所限制。

总结

通过这次实验,作者学到了几个重要的经验: - 现代存储设备的并行性至关重要,传统的I/O接口隐藏了这种并行性。 - 批处理是提高性能的关键。 - 通过将意图与完成分离,可以在保持强一致性保证的同时实现更高的性能。 - 更复杂的恢复算法可以简化运行时协议,提升操作性能。

这次实验改变了作者对数据库架构的思考方式,表明I/O可以变得廉价且并行,许多传统设计决策需要重新考虑。硬件一直是并行的,我们只需要能够利用它的软件架构。

评论总结

评论主要围绕使用io_uring构建数据库时的持久性(durability)问题展开,观点分为支持和质疑两派。

支持观点: 1. iouring提升性能:评论5提到,使用iouring可以显著提高吞吐量,并分享了一种通过WAL(Write-Ahead Log)和fsync实现崩溃恢复的方法。 - "Great to see someone going into this. I wanted to do a simple LSM tree using io_uring in Zig for some time but couldn't get into it yet." - "First append to WAL file. Start fsync call on the WAL file, create a new hash/length file with different name and fsync it in parallel."

  1. 异步I/O的优势:评论8指出,异步I/O可以提高性能,但需要确保数据持久性。
    • "The problem with naive async I/O in a database context at least, is that you lose the durability guarantee that makes databases useful."
    • "Shouldn't you just tie the successful response to a successful fsync?"

质疑观点: 1. 持久性不足:评论3、7、9和11质疑文章中的方法无法保证持久性,认为异步写入可能导致数据丢失。 - "Does this mean that a client could receive a success for a request, which if the system crashed immediately afterwards, when replayed, wouldn’t necessarily have that request recorded?" - "The protocol violates durability, because once the client receives success from server, it should be durable." - "First, I think the article provides false claim, the solution doesn't guarantee durability."

  1. fsync的必要性:评论11强调,fsync是确保数据持久性的关键,文章中的性能提升可能只是因为没有使用fsync。
    • "They are not comparing performance of sync APIs vs io_uring. They're comparing using fsync vs not using fsync!"
    • "If you just removed the fsync from the sync code you'd quite possibly get a speedup of an order of magnitude too."

其他观点: 1. 技术细节讨论:评论2和6讨论了WAL的实现细节,质疑双WAL操作的效率。 - "But then I don't see the point of logging the intent record separately." - "I don't get this. How can two(+) WAL operations be faster than one (double the sync IOPS)?"

  1. 其他系统对比:评论10提到TigerBeetle的实现方式,强调其通过fsync和复杂的恢复机制确保持久性。
    • "For example, we never externalize commits without full fsync, to preserve durability."
    • "Finally, TigerBeetle's recovery is more intricate, we do all this to survive TigerBeetle's storage fault model."

总结:评论中对io_uring的性能提升持肯定态度,但对其在数据库持久性方面的实现提出了质疑,特别是关于fsync的使用和异步写入的可靠性。