`
carlosfu
  • 浏览: 571530 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Ba8b5055-9c58-3ab0-8a1c-e710f0495d2c
BigMemory实战与理...
浏览量:29989
53b2087e-c637-34d2-b61d-257846f73ade
RedisCluster开...
浏览量:149067
C9f66038-7478-3388-8086-d20c1f535495
缓存的使用与设计
浏览量:122664
社区版块
存档分类
最新评论

linux 同步IO: sync、fsync与fdatasync(转载)

阅读更多

 

原文:http://blog.csdn.net/cywosp/article/details/8767327

 

一、UNIX写盘操作模型。 

 

     1. 传统的UNIX实现在内核中设有缓冲区高速缓存或页面高速缓存,大多数磁盘I/O都通过缓冲进行。当将数据写入文件时,内核通常先将该数据复制到其中一个缓冲区中,如果该缓冲区尚未写满,则并不将其排入输出队列,而是等待其写满或者当内核需要重用该缓冲区以便存放其他磁盘块数据时,再将该缓冲排入输出队列,然后待其到达队首时,才进行实际的I/O操作。这种输出方式被称为延迟写(delayed write)(Bach [1986]第3章详细讨论了缓冲区高速缓存)。

      
     2. 延迟写减少了磁盘读写次数,但是却降低了文件内容的更新速度,使得欲写到文件中的数据在一段时间内并没有写到磁盘上。当系统发生故障时,这种延迟可能造成文件更新内容的丢失。为了保证磁盘上实际文件系统与缓冲区高速缓存中内容的一致性,UNIX系统提供了sync、fsync和fdatasync三个函数。

  •     sync函数只是将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束, 通常称为update的系统守护进程会周期性地(一般每隔30秒)调用sync函数。这就保证了定期冲洗内核的块缓冲区。命令sync(1)也调用sync函数。
  •     fsync函数只对由文件描述符filedes指定的单一文件起作用,并且等待写磁盘操作结束,然后返回。fsync可用于数据库这样的应用程序,这种应用程序需要确保将修改过的块立即写到磁盘上。
  •     fdatasync函数类似于fsync,但它只影响文件的数据部分。而除数据外,fsync还会同步更新文件的属性。

 

二、sync、fsync,fdatasync详细分析

 

  对于提供事务支持的数据库,在事务提交时,都要确保事务日志(包含该事务所有的修改操作以及一个提交记录)完全写到硬盘上,才认定事务提交成功并返回给应用层。

   一个简单的问题:在*nix操作系统上,怎样保证对文件的更新内容成功持久化到硬盘?

 

1.  write不够,需要fsync

       一般情况下,对硬盘(或者其他持久存储设备)文件的write操作,更新的只是内存中的页缓存(page cache),而脏页面不会立即更新到硬盘中,而是由操作系统统一调度,如由专门的flusher内核线程在满足一定条件时(如一定时间间隔、内存中的脏页达到一定比例)内将脏页面同步到硬盘上(放入设备的IO请求队列)。
      因为write调用不会等到硬盘IO完成之后才返回,因此如果OS在write调用之后、硬盘同步之前崩溃,则数据可能丢失。虽然这样的时间窗口很小,但是对于需要保证事务的持久化(durability)和一致性(consistency)的数据库程序来说,write()所提供的“松散的异步语义”是不够的,通常需要OS提供的同步IO(synchronized-IO)原语来保证:
#include <unistd.h>
2 int fsync(int fd);
 
    fsync的功能是确保文件fd所有已修改的内容已经正确同步到硬盘上,该调用会阻塞等待直到设备报告IO完成。
    PS:如果采用内存映射文件的方式进行文件IO(使用mmap,将文件的page cache直接映射到进程的地址空间,通过写内存的方式修改文件),也有类似的系统调用来确保修改的内容完全同步到硬盘之上:
1 #incude <sys/mman.h>
2 int msync(void *addr, size_t length, int flags)
 

    msync需要指定同步的地址区间,如此细粒度的控制似乎比fsync更加高效(因为应用程序通常知道自己的脏页位置),但实际上(Linux)kernel中有着十分高效的数据结构,能够很快地找出文件的脏页,使得fsync只会同步文件的修改内容。

 

2. fsync的性能问题,与fdatasync

    除了同步文件的修改内容(脏页),fsync还会同步文件的描述信息(metadata,包括size、访问时间st_atime & st_mtime等等),因为文件的数据和metadata通常存在硬盘的不同地方,因此fsync至少需要两次IO写操作,fsync的man page这样说
"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的功能与fsync类似,但是仅仅在必要的情况下才会同步metadata,因此可以减少一次IO写操作。那么,什么是“必要的情况”呢?根据man page中的解释:
"fdatasync does not flush modified metadata unless that metadata is needed in order to allow a subsequent data retrieval to be corretly handled."
 
    举例来说,文件的尺寸(st_size)如果变化,是需要立即同步的,否则OS一旦崩溃,即使文件的数据部分已同步,由于metadata没有同步,依然读不到修改的内容。而最后访问时间(atime)/修改时间(mtime)是不需要每次都同步的,只要应用程序对这两个时间戳没有苛刻的要求,基本无伤大雅。
    PS:open时的参数O_SYNC/O_DSYNC有着和fsync/fdatasync类似的语义:使每次write都会阻塞等待硬盘IO完成。(实际上,Linux对O_SYNC/O_DSYNC做了相同处理,没有满足Posix的要求,而是都实现了fdatasync的语义)相对于fsync/fdatasync,这样的设置不够灵活,应该很少使用。
 
 

3. 使用fdatasync优化日志同步

    文章开头时已提到,为了满足事务要求,数据库的日志文件是常常需要同步IO的。由于需要同步等待硬盘IO完成,所以事务的提交操作常常十分耗时,成为性能的瓶颈。
在Berkeley DB下,如果开启了AUTO_COMMIT(所有独立的写操作自动具有事务语义)并使用默认的同步级别(日志完全同步到硬盘才返回),写一条记录的耗时大约为5~10ms级别,基本和一次IO操作(10ms)的耗时相同。
 
   我们已经知道,在同步上fsync是低效的。但是如果需要使用fdatasync减少对metadata的更新,则需要确保文件的尺寸在write前后没有发生变化。日志文件天生是追加型(append-only)的,总是在不断增大,似乎很难利用好fdatasync。
    且看Berkeley DB是怎样处理日志文件的:
1.每个log文件固定为10MB大小,从1开始编号,名称格式为“log.%010d"
2.每次log文件创建时,先写文件的最后1个page,将log文件扩展为10MB大小
3.向log文件中追加记录时,由于文件的尺寸不发生变化,使用fdatasync可以大大优化写log的效率
4.如果一个log文件写满了,则新建一个log文件,也只有一次同步metadata的开销
      这三个系统调用都简单的介绍完,那么为什么需要它们三个呢?最简单的说是从应用的需求来考虑的,sync是全局的,对整个系统都flush,fsync值针对单个文件,fdatasync当初设计是考虑到有特殊的时候一些基本的元数据比如atime,mtime这些不会对以后读取造成不一致性,因此少了这些元数据的同步可能会在性能上有提升(但fsync和fdatasync两者的性能差别有多大?这个不知道有谁测过没)。所以说三者是根据不同的需求而定的。

        接下来谈谈flush dirty page,也就是前面说的同步写(没写完的话阻塞后面,直到写完才返回)。为什么是刷脏页?脏页表示缓存中的页(一般也就是内存中)也物理设备上的页处于不一致,不一致是由于在内存中被修改。所以为了使内存中的修改持久化到物理磁盘上我们需要将其从内存中flush到物理磁盘上。根据我的理解,一般来说缓存分成这几种:1>应用程序自己带了缓存,比如InnoDB的buffer pool;2>os层面上的缓存 ;3>磁盘设备自己的缓存,比如raid卡一般都管理着自己的缓存;4>磁盘本身或许会有一点点缓存(这个不确定,自己猜想的,这个即使有估计也是极小的)。好了,那么大部分的时候我们说的flush dirty page都是指从应用程序的缓存->os的缓存->物理设备,如果物理设备没有缓存的话,此时也就相当于持久化成功,但是像磁盘做了raid,raid卡有缓存的话,实际上还没真正持久化成功,因为此时还只到了raid卡的缓存,没到物理设备,但是由于raid卡一般都带有备用电池,所以即使此时断电也不会造成数据丢失。

        刚才说了很多时候应用自己也有缓存机制,那么你是否想过此时与os的缓存有重复呢?答案是:会的。刚才说了我是通过研究MySQL的一个参数innodb_flush_method注意这些的,innodb_flush_method表示flush策略,MySQL提供了fdatasync/O_DSYNC/O_DIRECT这三个选项,默认是fdatasync(详情可参看博文)我这里主要说明为什么会提供选项:O_DIRECT。这个选项告诉os,InnoDB在读写数据的时候都不经过os的缓存,因为刚才说过InnoDB会维护自己的缓存buffer pool,如果还使用os的缓存那么两者就会有一定的重复。在前面参考的文章里面说O_DIRECT对大量随即读写有效率提升,顺序读写则会下降。所以根据自己的需求来定,不过如果你的MySQL用在是OLTP上,基本上选择O_DIRECT没错。

 

三、dirty page解释:

 

由于页高速缓存的缓存作用,写操作实际上会被延迟,当页高速缓存中的数据比后台存储的数据更新时,该数据被称为脏数据。以下情况下脏页被写回磁盘:

1)当空闲内存低于一个特定的阈值时

2)当脏页在内存中驻留时间超过一个特定的阈值时

写回操作是由一组可并行执行的内核线程完成,这类线程叫做pdflush线程。

 

 

  • 大小: 132.8 KB
分享到:
评论

相关推荐

    函数sync、fsync与fdatasync的总结整理(必看篇)

    下面小编就为大家带来一篇函数sync、fsync与fdatasync的总结整理(必看篇)。小编觉得挺不错的。现在就分享给大家。也给大家做个参考。一起跟随小编过来看看吧

    s3-folder-sync:围绕s3-sync的命令行包装器

    LOKE用于将静态网站内容与S3存储桶同步。 用法 s3fsync directory 例如,同步当前目录运行: s3fsync . 这将需要将S3目标详细信息配置为环境变量(请参见下文)。 或者,您可以将凭据指定为命令行参数: s3...

    文件夹同步软件fsync中文注册版

    好用的文件夹比较,同步软件,适用于所用软件及数据增量备份恢复。

    Linux内核驱动fsync机制实现图解.docx

    Linux内核驱动fsync机制实现图解.docx

    Linux系统调用fsync函数详解.docx

    Linux系统调用fsync函数详解.docx

    linux笔记相关vim命令

    linux笔记相关vim命令

    toom-study

    AOF文件的写入与同步:内部服务器常规任务函数被执行,或事件处理器被执行时,aof.c / flushAppendOnlyFile函数都会被调用,这个函数执行以下两个工作:WRITE:根据条件,将aof_buf中的缓存写入到AOF文件。...

    FSync:用于工作区之间文件同步的 Sublime Text 3 插件

    同步 用于工作区之间文件同步的 Sublime Text 3 插件 如何安装 使用 github 存储库和包控制 使用Package Control ,在下面添加存储库(Preferences &gt; Package Control &gt; Add Repository)并正常安装FSync包。 ...

    Linux驱动开发——内核同步方法

    共享资源需要保护,防止被并发访问。共享资源之所以需要防止被并发访问,是因为如果多个执行线程同事访问和操作数据,就有可能发生个线程之间相互覆盖共享数据的情况,造成被访问数据处于不一直状态。...

    Understanding the Linux Kernel

     sync()、fsync()和fdatasync()系统调用  第十六章访问文件  读写文件  内存映射  直接I/O传送  异步I/O  第十七章回收页框  页框回收算法  反向映射  PFRA实现  交换  第十八章Ext2和Ext3文件系统  ...

    fsync:FTP文件同步管理器,基于带有FTPimp的NodeJS构建

    FTP同步 基于浏览器的FTP文件同步管理器,使用NodeJS和FTPimp构建。 设置 将config/config.sample.js复制到config/config.js并根据需要更改config/config.js值 将config/ftp.sample.js复制到config/ftp.js并根据需要...

    深入理解LINUX内核(影印版)(第3版)

    The sync( ), fsync( ), and fdatasync( ) System Calls Chapter 16. Accessing Files Section 16.1. Reading and Writing a File Section 16.2. Memory Mapping Section 16.3. Direct I/O Transfers ...

    node.js中的fs.fsync方法使用说明

    同步磁盘缓存。 语法: 代码如下: fs.fsync(fd, [callback(err)]) 由于该方法属于fs模块,使用前需要引入fs模块(var fs= require(“fs”) ) 接收参数: fd 文件描述符 callback 回调,传递一个异常参数err ...

    Linux内核源代码导读-陈香兰-ext2文件系统

    Linux内核源代码导读-陈香兰-中国科学技术大学-ext2文件系统

    linux510-vd:适用于Arch兼容发行版Linux 5.10

    Steam futex / fsync补丁 SirLucjan回购中的补丁 清除Linux补丁 模块,内核和initram压缩的优化默认值 稍微调整vm / vfs / cfs设置 归功于所有内核开发人员和: 霍尔格·霍夫施塔特(HolgerHoffstätte) 卢肯爵士...

    libeatmydata:libeatmydata-因为fsync()应该是no-op

    fsync()变为NO-OP,O_SYNC被删除等。 这个想法是在测试中使用,以在不需要真正耐用性的情况下获得更快的测试运行速度。 不要在关心软件存储内容的软件上使用libeatmydata。 由于某种原因,它被称为lib EAT-MY-...

    在Windows与Linux下禁止被ping的设置方法[推荐]

    LINUX下禁止ping命令的使用 以root进入Linux系统,然后编辑文件icmp_echo_ignore_allvi /proc/sys/net/ipv4/icmp_echo_ignore_all将其值改为1后为禁止PING将其值改为0后为解除禁止PING 直接修改会提示错误: WARNING:...

    fsync-encode-decode:用于特定数据突发格式的软件调制解调器

    fsync-编码-解码用于特定数据突发格式的软件调制解调器该库支持以 1200 和 2400 bps 对 Kenwood 的 FleetSync 和 FleetSync II 格式进行解码(编码将在以后的版本中添加)。 (其各自所有者的所有商标财产) GPL ...

Global site tag (gtag.js) - Google Analytics