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