"Unfortunately fsync() will always initialize two write operations : one for the newly written data and another one in order to update the modification time stored in the inode. If the modification time is not a part of the transaction concept fdatasync() can be used to avoid unnecessary inode disk write operations."
多余的一次IO操作,有多么昂贵呢?根据Wikipedia的数据,当前硬盘驱动的平均寻道时间(Average seek time)大约是3~15ms,7200RPM硬盘的平均旋转延迟(Average rotational latency)大约为4ms,因此一次IO操作的耗时大约为10ms左右。这个数字意味着什么?下文还会提到。
Posix同样定义了fdatasync,放宽了同步的语义以提高性能:
1 #include <unistd.h> 2 int fdatasync(int fd);
"fdatasync does not flush modified metadata unless that metadata is needed in order to allow a subsequent data retrieval to be corretly handled."
在Berkeley DB下,如果开启了AUTO_COMMIT(所有独立的写操作自动具有事务语义)并使用默认的同步级别(日志完全同步到硬盘才返回),写一条记录的耗时大约为5~10ms级别,基本和一次IO操作(10ms)的耗时相同。
1.每个log文件固定为10MB大小,从1开始编号,名称格式为“log.%010d"2.每次log文件创建时,先写文件的最后1个page,将log文件扩展为10MB大小3.向log文件中追加记录时,由于文件的尺寸不发生变化,使用fdatasync可以大大优化写log的效率4.如果一个log文件写满了,则新建一个log文件,也只有一次同步metadata的开销
int fflush(FILE *stream)
libc.a中提供的方法,是把C库中的缓冲调用write函数写到磁盘[其实是写到内核的缓冲区]。
int fsync(int fd)
系统提供的系统调用,是把内核缓冲刷到磁盘上。
c库缓冲 ------ fflush------>内核缓冲 ------fsync ------>磁盘