传统的UNIX实现在内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘I/O都通过缓冲进行。当将数据写入文件时,内核通常先将该数据复制到其中一个缓冲区中,如果该缓冲区尚未写满,则并不将其排入输出队列,而是等待其写满或者当内核需要重用该缓冲区以便存放其他磁盘块数据时,再将该缓冲排入输出队列,然后待其到达队首时,才进行实际的I/O操作。这种输出方式被称为延迟写(delayed write)(Bach [1986]第3章详细讨论了缓冲区高速缓存)。
延迟写减少了磁盘读写次数,但是却降低了文件内容的更新速度,使得欲写到文件中的数据在一段时间内并没有写到磁盘上。当系统发生故障时,这种延迟可能造成文件更新内容的丢失。为了保证磁盘上实际文件系统与缓冲区高速缓存中内容的一致性,UNIX系统提供了sync、fsync和fdatasync三个函数。
sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。
通常称为update的系统守护进程会周期性地(一般每隔30秒)调用sync函数。这就保证了定期冲洗内核的块缓冲区。命令sync(1)也调用sync函数。
fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。fsync可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘上。
fdatasync函数类似于fsync,但它只影响文件的数据部分。而除数据外,fsync还会同步更新文件的属性。
对于提供事务支持的数据库,在事务提交时,都要确保事务日志(包含该事务所有的修改操作以及一个提交记录)完全写到硬盘上,才认定事务提交成功并返回给应用层。
一个简单的问题:在*nix操作系统上,怎样保证对文件的更新内容成功持久化到硬盘?
1. write不够,需要fsync
1 #include <unistd.h>
2 int fsync(int fd);
1 #incude <sys/mman.h>
2 int msync(void *addr, size_t length, int flags)
msync需要指定同步的地址区间,如此细粒度的控制似乎比fsync更加高效(因为应用程序通常知道自己的脏页位置),但实际上(Linux)kernel中有着十分高效的数据结构,能够很快地找出文件的脏页,使得fsync只会同步文件的修改内容。
2. fsync的性能问题,与fdatasync
"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."
3. 使用fdatasync优化日志同步
在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的开销
相关推荐
在IT领域,尤其是在操作系统和文件系统管理中,`sync`、`fsync`和`fdatasync`是三个至关重要的函数,它们用于确保数据的安全写入和系统一致性。以下是这三个函数的详细说明: 1. **sync函数**: `sync`函数的作用...
### 漫谈 Linux 文件 I/O #### 一、引言 在 Linux 开发领域,技术人员尤为关注几个关键性能指标:进程管理、CPU 使用率、内存占用、网络 I/O 和磁盘 I/O。其中,磁盘 I/O 性能尤其重要,因为它直接影响到系统的响应...
fsync 函数是 Linux 系统调用中的一种同步函数,用于将内存中所有已修改的文件数据同步到储存设备中。其主要功能是将内核缓存中的数据写入到磁盘上,以确保文件系统的一致性。 fsync 函数的用法为:`int fsync(int...
文件夹同步软件FSync中文注册版是一款高效且实用的工具,专为用户提供了方便快捷的文件和文件夹比较以及同步功能。在IT行业中,文件同步是至关重要的,尤其是在多设备协同工作、数据备份和恢复等领域。FSync软件以其...
LOKE用于将静态网站内容与S3存储桶同步。 用法 s3fsync directory 例如,同步当前目录运行: s3fsync . 这将需要将S3目标详细信息配置为环境变量(请参见下文)。 或者,您可以将凭据指定为命令行参数: s3...
### 嵌入式软件工程师面经:深入理解Linux下的文件与设备IO #### 一、文件IO(File I/O) 文件输入/输出(File I/O)是操作系统中最基础且重要的功能之一,它处理的是文件系统层面的数据读写操作。下面详细介绍文件...
Linux内核驱动fsync机制实现图解可以分为四个方面:同步阻塞I/O、同步非阻塞I/O、异步阻塞I/O和异步非阻塞I/O。 同步阻塞I/O:应用程序显式地通过函数访问数据,在此函数返回时就会得到结果(成功或失败)。在这种...
本主题将深入探讨Linux文件IO操作例程,帮助你理解如何在C语言环境中使用这些函数来读写文件,创建、打开、关闭以及管理文件。 1. **打开文件**: Linux提供`open()`函数来打开文件。它接受两个参数:文件路径和一...
本文总结了C++面试题网络编程篇中的重要知识点,包括dup和dup2函数、lseek函数、sync、fsync和fdatasync函数、fcntl函数、exit和_exit函数、setjmp和longjmp函数、记录锁、守护进程编程规范等。 1. dup和dup2函数 ...
本章详细介绍了Linux系统编程中的文件I/O操作,包括文件的打开与创建、读写操作、同步机制等内容。通过学习这些基本概念和技术,读者可以更好地理解和掌握如何在Linux环境下进行高效的文件操作。下一章节将进一步...
- **2.4.1 fsync() 与 fdatasync()**:这两个函数用于同步文件内容和元数据到磁盘。 - **2.4.2 文件同步与缓存同步**:在同步文件时,需要考虑文件内容与缓存之间的同步问题。 - **2.4.3 sync() 系统调用**:`...
- **2.4.1 fsync()与fdatasync()**:`fsync()`用于强制将与文件描述符关联的所有数据写入磁盘;`fdatasync()`只同步文件数据,不包括元数据。 - **2.4.2 数据同步**:为了确保数据一致性,在关键操作前后应调用`...