Linux 上的异步 I/O 与耐久性

主要观点:作者在复杂多模型数据库工作数周后,简化并测试简单键值数据库的想法。起初用传统方法,后阅读关于 io_uring 的资料并进行实验,发现其能暴露磁盘并行性,提高吞吐量,但也遇到一致性问题。通过重新思考预写日志(WAL),采用双 WAL 设计(意图 WAL 和完成 WAL),在简单内存键值数据库中实验,取得显著效果,吞吐量提升 10 倍且能随 CPU 核心数扩展,还总结出硬件并行性重要、批处理关键、一致性模型灵活、恢复可复杂等经验,此实验改变了对数据库架构的看法。

关键信息:

  • 传统 I/O 接口同步,现代存储硬件并行,io_uring 通过共享环缓冲区暴露并行性。
  • 数据库中 naive async I/O 会丢失耐久性保证,需更好方法,如双 WAL 设计。
  • 双 WAL 设计:意图 WAL 记录操作意图,完成 WAL 记录操作完成,恢复时只应用有两者记录的操作。
  • 实现双 WAL 系统需注意分离 io_uring 实例、使用循环缓冲区批处理等细节,恢复过程更复杂但更稳健。
  • 双 WAL 设计虽增加单个操作延迟,但在批量处理时性能提升显著,io_uring 设计与双 WAL 方法配合完美。

重要细节:

  • 最初用内存哈希表、只追加日志和每次写日志后 fsync()保证耐久性,虽有效但不够快。
  • 读关于 io_uring 的资料后进行实验,将同步写改为异步写,吞吐量立即提升一个数量级,但出现一致性问题。
  • 初始解决方案是跟踪待处理 I/O 操作,等完成记录到达才返回成功,又回到等待磁盘 I/O。
  • 双 WAL 设计中每个完成记录包括校验和和指向对应意图记录的引用,恢复时通过哈希图链接两者。
  • 批处理时可一次提交多个意图记录,同时处理内存操作,一次提交所有完成记录并等待完成,降低每个操作的平均成本。
  • 实验结果超出预期,吞吐量提升 10 倍,系统能随 CPU 核心数扩展,io_uring 减少 I/O 竞争和系统调用开销。
阅读 10
0 条评论