linux - 可以在每次提交时使用单个 fsync 来实现日志记录吗?

标签 linux fsync journaling

假设您正在构建一个日志/预写日志存储系统。您可以通过(对于每个事务)附加数据(使用 write(2))、附加提交标记,然后进行 fsync 来简单地实现这一点吗?

要考虑的场景是,如果您对此日志进行大量写入,然后对其进行 fsync,并且在 fsync 期间发生故障。 inode 直接/间接 block 指针是否仅在刷新所有数据 block 后才刷新,或者是否不能保证 block 按顺序刷新?如果是后者,那么在恢复期间,如果您在文件末尾看到提交标记,则不能相信它与前一个提交标记之间的数据是有意义的。因此,您必须依赖另一种机制(至少涉及另一个 fsync)来确定日志文件的一致程度(例如,写入/fsyncing 数据,然后写入/fsyncing 提交标记)。

如果有什么不同,主要是想知道 ext3/ext4 作为上下文。

最佳答案

请注意,linux 和 mac os 的 fsync 和 fdatasync 默认情况下是不正确的。 Windows 默认情况下是正确的,但可以模拟 Linux 进行基准测试。

此外,如果您追加到文件末尾,fdatasync 会发出多个磁盘写入操作,因为它需要使用新长度更新文件 inode。如果您希望每次提交写入一次,最好的选择是预先分配日志空间,在提交标记中存储日志条目的 CRC,并在提交时发出单个 fdatasync()。这样,无论操作系统/硬件在背后重新排序多少,您都可以找到实际命中磁盘的日志的前缀。

如果您想使用日志进行持久提交或预写,事情会变得更困难,因为您需要确保 fsync 确实有效。在 Linux 下,您需要使用 hdparm 禁用磁盘写入缓存,或者挂载屏障设置为 true 的分区。 [编辑:我纠正了,屏障似乎没有给出正确的语义。 SATA 和 SCSI 引入了许多原语,例如写屏障和 native 命令队列,使操作系统可以导出启用预写日志记录的原语。从我从联机帮助页和在线信息来看,Linux 只向文件系统开发人员公开这些内容,而不向用户空间公开这些内容。]

矛盾的是,禁用磁盘写入缓存有时会带来更好的性能,因为您可以更好地控制用户空间中的写入调度;如果磁盘将一堆同步写入请求排队,最终会给应用程序带来奇怪的延迟峰值。禁用写入缓存可以防止这种情况发生。

最后,真实系统使用组提交,并在并发工作负载下每次提交执行 <1 次同步写入。

关于linux - 可以在每次提交时使用单个 fsync 来实现日志记录吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3800108/

相关文章:

c++ - mbstowcs() 因特殊字符而失败

linux - 如何记录通过 ssh 发送的非交互式 bash 命令

python - 在 stdout/stderr 文件描述符上调用 os.fsync 会杀死一个子进程

c# - 类似于文件系统日志记录或容错日志记录的过程来管理任务?

mongodb - MongoDB 日志是如何工作的

django - Gunicorn 因 203/EXEC 失败

linux - 使用 Ncat 将数千行逐一发送到套接字服务器?

fflush - fflush 和 fsync 的区别

linux - 我们是否需要 fsync UBIFS 中的父目录以进行原子 * 和 * 持久文件更新

filesystems - 可以删除 NTFS USN 日志中的单个条目吗?