一、缓冲

操作系统实现某些文件I/O时,为了保证I/O效率,内核中都设置有缓冲区(OS Cache)或页面高速缓冲区,大多数磁盘IO都是通过缓冲写的。
延迟写:

  1. 当你想将数据write进文件时,内核通常会将该数据复制到其中一个缓冲区中,如果该缓冲没被写满的话,内核就不会把它放入到输出队列中。
  2. 当这个缓冲区被写满或者内核想重用这个缓冲区时,才会将其排到输出队列中。等它到达等待队列首部时才会进行实际的IO操作。

Linux I/O sync、fsync和fdatasync函数 - 图1

二、延迟写的优缺点

  • 优点:
    • 降低了磁盘读写的次数,保证I/O效率。
  • 缺点:
    • 降低了文件的更新速度。
    • 可能会造成文件更新内容的丢失。

为了保证磁盘上的实际文件和缓冲区中的内容保持一致,UNIX系统提供了三个系统调用:sync、fsync、fdatasync

三、sync、fsync、fdatasync

  1. #include<unistd.h>
  2. int sync();
  3. int fsync(int filedes);
  4. int fdatasync(int filedes);
  • sync系统调用:将所有修改过的缓冲区排入写队列,然后就返回,它并不等实际的写磁盘的操作结束。所以它的返回并不能保证数据的安全性。通常会有一个系统守护进程update每隔30s调用一次sync。
    • 特点:因为不等队列写磁盘完成即返回,性能好。但掉电丢数据风险。
  • fsync函数只对由文件描符filedes指定的单一文件起作用,强制刷新指定filedes给出的文件的所有信息,并且等待写磁盘操作结束,然后返回。调用 fsync()的进程将阻塞直到设备报告传送已经完成。
    • 特点:修复掉电丢数据风险,即刷新filedes给出的文件所有信息,并等写磁盘操作结束返回。但性能差。
  • fdatasync函数类似于fsync函数,但它只影响文件数据部分,强制传送用户已写出的数据至物理存储设备,不包括文件本身的特征数据.这样可以适当减少文件刷新时的数据传送量。而除数据外,fdatasync还会同步更新文件的属性.
    • 特点:修复掉电丢数据风险,只刷新data部分,不包含文件特征部分。性能较fsync好,比sync差。

一个程序在写出数据之后,如果继续进行后续处理之前要求确保所写数据已写到磁盘,则应当调用fsync()。例如,数据库应用通常会在调用write()保存关键交易数据的同时也调用fsync()。这样更能保证数据的安全可靠。

fsync系统调用:需要你在入参的位置上传递给他一个fd,然后系统调用就会对这个fd指向的文件起作用。fsync会确保一直到写磁盘操作结束才会返回。所以fsync适合数据库这种程序。