假设您正在构建日记/预写日志记录存储系统。你能简单地通过(对于每个事务)附加数据(使用write(2)),附加提交标记,然后fsyncing来实现吗?
要考虑的方案是,如果您对此日志执行大量写入操作,然后对其进行fsync,并且在fsync 期间出现失败。仅在刷新所有数据块之后才刷新inode直接/间接块指针,或者是否不保证按顺序刷新块?如果是后者,那么在恢复期间,如果在文件末尾看到提交标记,则不能相信它与前一个提交标记之间的数据是有意义的。因此,您必须依赖另一种机制(至少涉及另一个fsync)来确定日志文件的范围是一致的(例如,写入/ fnyncing数据,然后写入/ fsyncing提交标记)。
如果它有所不同,主要是想知道ext3 / ext4作为上下文。
答案 0 :(得分:4)
请注意,默认情况下,linux和mac os的fsync和fdatasync不正确。 Windows默认是正确的,但可以模拟linux以进行基准测试。
此外,如果附加到文件末尾,fdatasync会发出多个磁盘写入,因为它需要使用新长度更新文件inode。如果您希望每次提交一次写入,最好的办法是预先分配日志空间,在提交标记中存储日志条目的CRC,并在提交时发出单个fdatasync()。这样,无论操作系统/硬件在您的背后重新排序多少,您都可以找到实际命中磁盘的日志前缀。
如果你想使用日志进行持久提交或提前写,事情会变得更加困难,因为你需要确保fsync确实有效。在Linux下,您需要使用hdparm禁用磁盘写入缓存,或者将barrier设置为true的分区。 [编辑:我站得更正,屏障似乎没有给出正确的语义。 SATA和SCSI引入了许多原语,例如写入障碍和本机命令队列,这使得操作系统可以导出启用预写日志记录的原语。从我从联机帮助页和联机中可以看出,Linux只向文件系统开发人员公开,而不是向用户空间公开。]
矛盾的是,禁用磁盘写入缓存有时会带来更好的性能,因为您可以更好地控制用户空间中的写入调度;如果磁盘将一堆同步写入请求排队,则最终会向应用程序暴露出奇怪的延迟峰值。禁用写入缓存会阻止这种情况发生。
最后,真实系统使用组提交,并且<每次提交1个同步写入和并发工作负载。
答案 1 :(得分:1)
无法保证将块刷新到磁盘的顺序。如今,即使是驱动器本身也可以在通往盘片的路上重新订购。
如果要强制执行排序,则需要在要订购的写入之间至少fdatasync()
。所有同步承诺是返回时,在同步之前写入的所有内容都已存储。