【问题标题】:Can I use O_DIRECT for write requests to avoid data loss during power failure?是否可以使用 O_DIRECT 进行写请求以避免断电时数据丢失?
【发布时间】:2011-04-23 09:03:27
【问题描述】:

我们想尽最大努力避免断电时数据丢失。所以我决定使用 O_DIRECT 标志打开一个文件来将数据写入磁盘。 O_DIRECT 是否意味着数据完全绕过操作系统缓存?如果请求返回给应用程序成功,是否意味着数据一定已经刷到磁盘了?如果我在一个文件系统中打开一个常规文件,FS 元数据呢?是也立即刷新,还是缓存?

对了,O_DIRECT 可以在 Windows 中使用吗?或者windows里面有没有对应的方法?

【问题讨论】:

    标签: linux winapi io


    【解决方案1】:

    O_DIRECT 可能会执行您想要的操作,但会大大减慢您的 I/O。
    我认为根据您是使用直接文件描述符操作还是 FILE * 调用 fsync() 或 fflush() 就足够了。
    至于元数据问题,如果您想更加偏执,它取决于底层文件系统,甚至取决于硬件。硬盘驱动器(尤其是 SSD)可能会报告操作已完成,但实际写入数据可能需要一段时间。

    【讨论】:

    【解决方案2】:

    您可以使用 O_DIRECT,但对于许多应用程序,调用 fdatasync() 更方便。 O_DIRECT 施加了很多限制,因为 IO 完全绕过了 OS 缓存。它绕过了读缓存和写缓存。

    对于文件系统元数据,您所能做的就是在写入文件后对其进行 fsync()。 fsync 会刷新文件元数据,因此您可以确保如果之后立即断电,文件不会消失(或更改其属性等)。

    任何这些机制都取决于您的 IO 子系统,而不是向操作系统谎称将数据持久化到存储中,并且在许多情况下,其他依赖于硬件的事情(例如 RAID 控制器电池在电源恢复之前没有耗尽)

    【讨论】:

      【解决方案3】:

      CreateFile可以做到这一点。

      HANDLE WINAPI CreateFile(
        __in      LPCTSTR lpFileName,
        __in      DWORD dwDesiredAccess,
        __in      DWORD dwShareMode,
        __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
        __in      DWORD dwCreationDisposition,
        __in      DWORD dwFlagsAndAttributes,
        __in_opt  HANDLE hTemplateFile
      );
      

      对于dwFlagsAndAttributes,您可以指定FILE_FLAG_WRITE_THROUGHFILE_FLAG_NO_BUFFERING

      如果FILE_FLAG_WRITE_THROUGHFILE_FLAG_NO_BUFFERING 都是 指定,以便系统缓存是 无效,则数据为 立即刷新到磁盘没有 通过Windows系统 缓存。操作系统也 要求硬笔直写 磁盘的本地硬件缓存到 持久性媒体。

      【讨论】:

        【解决方案4】:

        是否可以使用 O_DIRECT 进行写入请求以避免断电时数据丢失?

        不!

        在 Linux 上,当O_DIRECT 试图绕过您的操作系统缓存时,它从不绕过您的磁盘缓存。如果您的磁盘具有易失性写入缓存,您仍然会丢失仅在突然断电期间仅在磁盘缓存中的数据!

        O_DIRECT 是否意味着数据完全绕过操作系统缓存?

        通常,但某些 Linux 文件系统可能会使用 O_DIRECTExt4 Wiki Clarifying Direct IO's Semantics page warns this can happen with allocating writes)回退到缓冲 I/O。

        如果请求返回给应用程序成功,是否意味着数据一定已经刷到磁盘了?

        这通常意味着磁盘已“看到”它,但请参阅上述警告(例如,数据可能已进入缓冲区缓存/数据可能仅在磁盘的易失性缓存中)。

        如果我在一个文件系统中打开一个常规文件,FS 元数据呢?是也立即刷新,还是缓存?

        很好的问题!即使请求成功完成,元数据仍可能在缓存中滚动并且尚未同步到磁盘。

        以上所有内容意味着如果您想确定操作是否已到达非易失性存储,您必须在正确的位置执行适当的fsync() 命令(并检查其结果!)。详情请参阅https://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/LWN article "Ensuring data reaches disk"

        【讨论】:

        • 只是添加另一个LWN article,这似乎表明即使fsync() 也不足以确保一致性,因为(如果我理解正确的话)即使fsync() 返回成功,它仍然可能发生了错误,没有写入任何内容。
        • @PeterJankuliak 肯定我应该输入“假设没有错误”,但fsync() 将是必要的,即使它还不够。请参阅stackoverflow.com/a/52177578 重述您的 LWN 文章。
        猜你喜欢
        • 2020-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-04
        • 2012-11-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多