linux中sync和direct的区别

[学习如逆水行舟,不进则退]
对于linux中一些常用的写操作,对比一下direct和sync的区别,后面会专门起个专题讲一下linux中的缓存机制和page cache
linux中sync和direct的区别
linux中sync和direct区别
o_direct
绕过缓冲区高速缓存,直接IO
直接IO:Linux允许应用程序在执行磁盘IO时绕过缓冲区高速缓存,从用户空间直接将数据传递到文件或磁盘设备,称为直接IO(direct IO)或者裸IO(raw IO)
应用场景:数据库系统,其高速缓存和IO优化机制均自成一体,无需内核消耗CPU时间和内存去完成相同的任务
弊端:可能会大大降低性能,内核对缓冲区告诉缓存做了不少优化,包括:按顺序预读取,在成簇磁盘块上执行IO,允许访问同一文件的多个进程共享高速缓存的缓冲区
注意可能发生的不一致性:若一进程以O_DIRECT标志打开某文件,而另一进程以普通(即使用了高速缓存缓冲区)打开同一文件,则由直接IO所读写的数据与缓冲区高速缓存中内容之间不存在一致性,应尽量避免这一场景
使用直接IO需要遵守的一些限制:
1、用于传递数据的缓冲区,其内存边界必须对齐为块大小的整数倍
2、数据传输的开始点,即文件和设备的偏移量,必须是块大小的整数倍
3、待传递数据的长度必须是块大小的整数倍。
不遵守上述任一限制均将导致EINVAL错误。
O_SYNC
以同步方式写入文件
功能:强制刷新内核缓冲区到输出文件。这是有必要的,因为为了数据安全,需要确保将数据真正写入磁盘或者磁盘的硬件告诉缓存中
同步IO的定义:某一IO操作,要么已成功完成到磁盘的数据传递,要么被诊断为不成功。
linux定义了两种同步IO完成类型:
1、确保针对文件的一次更新传递了足够的信息(部分文件元数据)到磁盘,以便于之后对数据的获取
2、确保针对文件的一次更新传递了所有的信息(所有文件元数据)到磁盘,即使有些在后续对文件数据的操作并不需要。
常用函数
fsync 作用:fsync()系统调用将使缓冲数据和fd相关的所有元数据都刷新到磁盘上
fdatasync 作用:fdatasync()系统调用的作用类似fsync(),只是强制文件处于synchronized IO data integrity compeletion状态。
sync系统调用 作用:sync()系统调用会使包含更新文件信息的所有内核缓冲区(即数据块、指针块、元数据等)刷新到磁盘上。
detail:若内容发生变化的内核缓冲区在30s内未经显式方式同步到磁盘上,则一条长期运行的内核线程会确保将其刷新到磁盘上。这一做法是为了规避缓冲区与相关磁盘文件内容长期处于不一致状态
使所有写入同步:O_SYNC 调用open后,每个write调用会自动将文件数据和元数据刷新到磁盘上,即按照Synchronized IO file integrity completion的要求执行写操作
两者区别:fdatasync()可能会减少磁盘操作的次数,由fsync()调用请求的两次变成一次。例如,修改了文件的数据,而文件大小不变,那么调用fdatasync调用请求只强制进行了数据更新,相比之下,fsync()调用会强制将元数据传递到磁盘上,而元数据和文件数据通常驻留在磁盘的不同区域,更新这些数据需要反复在整个磁盘上执行寻道操作
有无O_SYNC性能对比
场景:将一百万字节写入一个ext2文件系统上的新创建文件,比较写入时间
结果

结论
采用O_SYNC标志(或者频繁调用fsync(), fdatasync()或sync())对性能影响极大。
性能下降的直接表现为运行总用时大为增加:在缓冲区为1字节的情况下,运行时间相差1000多倍。
以O_SYNC标志执行写操作时运行总用时和CPU时间之间的巨大差异(1030 - 98.8),原因是系统在每个缓冲区中将数据向磁盘传递时会把程序阻塞起来
IO缓冲层次关系
首先,通过stdio库将用户数据传递到stdio缓冲区,该缓冲区位于用户态内存区。
当缓冲区填满,stdio库会调用write()系统调用,将数据传递到内核高速缓冲区,该缓冲区位于内核态内存区。
最终,内核发起磁盘操作

左侧虚线方框中为可于任何时刻显式强制刷新各类缓冲区的调用。
右侧所示为促使刷新自动化的调用:通过禁用stdio的缓冲,和在文件输出类的系统调用中启用同步,从而使每个write()调用立刻刷新到磁盘
区别
o_direct:任何读写操作都只在用户态地址空间和磁盘之间传送而不经过page cache
O_SYNC: 只影响写操作,block当前写进程,先从用户态内存写入page cache, 再从page cache写入磁盘,然后才返回到用户进程
O_DIRECT: 无缓冲的输入、输出
O_SYNC:以同步IO方式打开文件