Linux文件API的持久化保障( 二 )


使用O_DIRECT的直接I / Oopen()系统调用具有O_DIRECT选项 , 该选项旨在绕过操作系统的缓存 , 而直接对磁盘进行I / O 。 这意味着在许多情况下 , 应用程序的写调用将直接转换为磁盘命令 。 但是 , 通常这不能替代fsync或fdatasync , 因为磁盘本身可以自由延迟或缓存那些写入 。 更糟糕的是 , 在某些情况下 , 意味着O_DIRECT I / O会退回到传统的缓冲I / O上 。 最简单的解决方案是也使用O_DSYNC选项打开 , 这意味着在每次写入后都将有效地跟随fdatasync 。
sync_file_rangeLinux还具有sync_file_range , 它可以允许将文件的一部分刷新到磁盘而不是整个文件 , 并触发异步刷新 , 而不是等待它 。 但是 , 手册页指出它“极度危险” , 因此不鼓励使用它 。 用sync_file_range最好地描述了某些差异和危险 , 这是Yoshinori Matsunobu的有关其工作原理的文章 。
系统要求持久的I / O结论是 , 持久性I / O基本上有三种方法 。 所有这些都要求在首次创建文件时在包含目录上调
用fsync() 。

  1. 写入后使用fdatasync或fsync(最好使用fdatasync) 。
  2. 写在用O_DSYNC或O_SYNC(最好是O_DSYNC)打开的文件描述符上 。
  3. 具有RWF_DSYNC或RWF_SYNC标志的pwritev2(首选RWF_DSYNC) 。
一些随机性能观察它们许多差异很小 。
  1. 覆盖比追加快(快2-100%):追加涉及其他元数据更新 , 即使在进行系统逻辑调用之后 , 但效果的大小也有所不同 。 我的建议是为获得最佳性能 , 请调用fallocate()来预分配所需的空间 , 然后将其显式零填充并进行fsync 。 这样可以确保在文件系统中将块标记为“已分配” , 而不是“未分配” , 这是一个很小的改进(?2%) 。 此外 , 某些磁盘在首次访问某个块时可能会降低性能 , 这意味着零填充会导致较大的改进(?100%) 。 值得注意的是 , 这可能发生在AWS EBS磁盘(不是官方的 , 尚未确认)和GCP永久磁盘(官方的;已确认) 。
  2. 更少的系统调用更快5%):与O_DSYNC一起使用open或与RWF_SYNC一起使用pwritev2似乎要快一些 , 而不是显式调用fdatasync 。 怀疑这是因为系统调用开销稍少(一个调用而不是两个) 。 但是 , 两者之间的差异很小 。
【Linux文件API的持久化保障】更多阅读: