2

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

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

如果它有所作为,主要是想知道 ext3/ext4 作为上下文。

4

2 回答 2

4

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

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

如果您想将日志用于持久提交或提前写入,事情会变得更加困难,因为您需要确保 fsync 确实有效。在 Linux 下,您需要使用 hdparm 禁用磁盘写入缓存,或者将屏障设置为 true 来挂载分区。[编辑:我的立场是正确的,屏障似乎没有给出正确的语义。SATA 和 SCSI 引入了许多原语,例如写屏障和本机命令队列,使操作系统能够导出启用预写日志记录的原语。根据我从手册页和在线上了解到的情况,Linux 只将这些暴露给文件系统开发人员,而不是用户空间。]

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

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

于 2010-09-26T23:33:18.010 回答
1

无法保证将块刷新到磁盘的顺序。如今,即使是驱动器本身也可以在前往盘片的途中重新排序块。

如果要强制执行排序,则至少需要在fdatasync()要排序的写入之间进行。所有同步承诺是,当它返回时,同步之前写入的所有内容都已存储。

于 2010-09-26T23:12:07.177 回答