innodb_flush_method 的理解

转载自:

https://www.cndba.cn/bensoncd/article/2093

陶方在innodb_flush_method带来的性能影响中从实验角度比较了fdatasync,O_DSYNC和O_DIRECT在性能上的差异。本文将试图从Linux/Unix"文件I/O"(unbuffered I/O)的角度来解释innodb_flush_method是如何影响MySQL的I/O。【附附1

 

innodb_flush_log_at_trx_commit参数确定日志文件何时write、flush。

0:log buffer将每秒一次地写入log file中,并且log file的flush(刷到磁盘)操作同时进行。该模式下在事务提交的时候,不会主动触发写入磁盘的操作。

1:每次事务提交时MySQL都会把log buffer的数据写入log file,并且flush(刷到磁盘)中去,该模式为系统默认。

2:每次事务提交时mysql都会把log buffer的数据写入log file,但是flush(刷到磁盘)操作并不会同时进行。该模式下,MySQL会每秒执行一次 flush(刷到磁盘)操作。

 

innodb_flush_method 则确定日志及数据文件如何write、flush。在Linux下,innodb_flush_method可以取如下值:fdatasync, O_DSYNC, O_DIRECT,那这三个值分别是如何影响文件写入的?首先需要先来了解Linux的文件I/O是如何工作的。

 

先来看看Linux/Unix文件I/O的一个典型例子:(Linux 2.6.24测试,gcc编译)

/*       A test about syscall of File I/O

               Author:supu@TaobaoDBA

               [email protected] http://orczhou.com http://www.taobaodba.com

*/

#include   "stdlib.h"          /* for exit */

#include   "unistd.h"         /* for write fdatasync*/

#include   "fcntl.h"           /* for open  */

int main(void){

            int fd;

            if((fd=open("/home/zzx/test.file",O_WRONLY | O_APPEND | O_DSYNC))<0) { exit(1); }

       char buff[]="abcdef";

       if(write(fd,buff,6)!= 6){ exit(2);}

       if(fdatasync(fd)==-1) { exit(3);}

       exit(0);

}

 

程序描述了一般的文件I/O操作的三个过程open、write、fdatasync,分别是打开文件、写文件、flush操作(将文件在系统上的缓存刷到磁盘上)。

一、Open阶段

open("test.file",O_WRONLY|O_APPDENT|O_SYNC))

系统调用Open会为该进程一个文件描述符fd【附录2。这里使用 O_WRONLY|O_APPDENT|O_SYNC打开文件:

1.   O_WRONLY表示我们以"写"的方式打开,告诉内核我们需要向文件中写入数据;

2.   O_APPDENT告诉内核以"追加"的方式写文件;

3.   O_DSYNC告诉内核,当向文件写入数据的时候,只有当数据写到了磁盘时,写入操作才算完成(write才返回成功。也就是在写的时候就立刻调用flush操作)。同类的文件标志,还有O_SYNC,O_RSYNC,O_DIRECT。

Ø  O_SYNC比O_DSYNC更严格,不仅要求数据已经写到了磁盘,而且对应的文件属性(如文件长度、最后修改时间 等)也需要更新完成才算write操作成功。可见O_SYNC较之O_DSYNC要多做一些操作。

Ø  O_RSYNC表示文件读取时,该文件的OS cache必须已经全部flush到磁盘了【附录3】;

Ø  O_DIRECT打开文件,则读/写操作都会跳过OS cache,直接在device(disk)上读/写。因为没有了OS cache,所以会O_DIRECT降低文件的顺序读写的效率。0_SYNC 标记和 0_DIRECT标记的不同之处在于 0_SYNC 没有禁用操作系统层的缓存。

 

二、Write阶段

write(fd,buf,6)。在使用open打开文件获得文件描述符之后,我们就可以调用write函数来写入数据了,write会根据前面的open参数不同,而表现不同。

三、Flush阶段

fdatasync(fd) == -1

write操作后,还得调用了fdatasync来确保文件数据flush到disk上。fdatasync返回成功后,那么可以认为数据已经写到了磁盘上。像fdatasync()的函数还有fsync()、sync()。

Fsync()和fdatasync的区别等同于O_SYNC和O_DSYNC的区别。fsync刷新文件的数据同时包括元数据。

Sync函数表示将文件在OS cache中的数据排入写队列,并不确认是否真的写磁盘了,所以sync并不可以靠。

 

忽略文件打开的过程,通常我们会说“写文件”有两个阶段,一个是调用write称为写数据阶段(其实是受open的参数影响),调用fsync(或者fdatasync)称为flush阶段。

四、回到MYSQL

1、参数Innodb_flush_method(Linux)可以设定为:Fdatasync、O_DSYNC、O_DIRECT。我们看看这个三个参数是如何影响程序MySQL对日志和数据文件的操作:

 

Open log

Flush log

Open datafile

Flush data

Fdatasync

 

fsync()

 

fsync()

O_DSYNC

O_SYNC

   

fsync()

O_DIRECT

 

fsync()

O_DIRECT

fsync()

 

PS:O_DIRECT下数据文件写入操作会通知操作系统不要缓存数据,也不要用预读。直接从innodb buffer到磁盘。这个设置依然使用 fsync() 来刷新文件到磁盘. 而真正的完成还是在flush这步。

 

PS: 使用0_SYNC 标记的写操作,听起来可能跟写同时调用fsync()做的事情非常相似,但是它们两个的实现无论在操作系统层还是在硬件层都非常不同。用了0_SYNC 标记后,操作系统可能把”使用同步I/O”标记下传给硬件层,告诉设备不要使用缓存。另一方面,fsync() 把文件系统缓冲数据刷写到设备上,如果设备支持,紧接着会传递一个指令给设备刷新它自己的缓存(希望它是一个带电的缓存),所以,毫无疑问数据肯定记录在了物理媒介上。另一个不同是,用了0_SYNC的话,每个 write()或 pwrite() 操作都会在函数完成之前把数据同步到磁盘,完成前函数调用是阻塞的。相对来看,不用O_SYNC标记的写入调用fsync()允许写操作积累在设备缓存(使得每个写更快),然后一次性刷新所有的数据。

 

2、参数Innodb_flush_method(Linux)设定为不同值得时候,关于操作系统缓存的使用情况。

innodb_flush_method 的理解_第1张图片

3、参数的选择

 

fdatasync被认为是安全的,因为在MySQL总会调用fsync()flush数据。(不知道磁盘设备的缓存是否带电有没有影响安全性能)

 

O_DSYNC使用是有些风险的,有些OS会忽略该参数O_SYNC

 

O_DIRECTfdatasync和很类似,但是它会使用O_DIRECT来打开数据文件。有数据表明,如果是大量随机写入操作,O_DIRECT会提升效率。但是顺序写入和读取效率都会降低。所以使用O_DIRECT需要谨慎。 果使用 0_DIRECT 选项,通常需要带有写缓存的 RAID 卡,并且设置为 Write-Back策略因为这是典型的唯一能保持好性能的方法。当 InnoDB 和实际存储设备之间没有缓冲时使用0_DIRECT,例如当 RAID 卡没有写缓存时, 可能导致严重的性能下降。现在有了多个写线程,这个问题稍微小一点(并且 MySQL 5.5 提供了原生异步 1/0) 但是通常还是有问题。

 

几个新参数值:

littlesync        :此选项用于内部性能测试,目前不受支持。请自行承担风险。
nosync            :此选项用于内部性能测试,目前不受支持。请自行承担风险
O_DIRECT_NO_FSYNC :InnoDB在刷新I / O期间使用O_DIRECT,但稍后跳过fsync( )系统调用。 此设置适用于某些类型的文件系统,但不适用于其他文件系统。 例如,它不适合于XFS。 如果您不确定您使用的文件系统是否需要fsync( ),例如保留所有文件元数据,请改用O_DIRECT。

 

 

 

【附录1】文章需要你了解什么是系统调用参考。可以简单的理解为:系统调用是在内核之上的一层封装。由内核直接提供接口,系统调用需要陷入内核执行(内核态)。其中fdatasync就是一个系统调用,该系统调用可以通知OS立刻将OS Cache中的数据Flush到磁盘文件中。

【附录2】这时候内核会为该该进程打开的文件分配一个文件描述符,并将该文件描述符返回给该进程。在内核的文件表中新建一个文件项,标记文件状态、文件当前偏移、以及I节点(v节点)的位置,内核还会打开该文件的I节点(这里记录文件的操作的函数指针,例如读操作、写操作)。

【附录3O_RSYNC我的理解是,对于同一个文件描述符可以保证读数据安全。同一个文件描述符包括dupfcntl函数dup的文件描述符,即共用同一个文件表项。O_RSYNC不是我们今天关注的,暂时忽略

未解问题:

1.  O_DIRECT在哪些OS(或者FS)上能够正常工作?

 

但至少 GNU/Linux FreeBSD, 以及 Solaris (5.0 以后的新版本) 是支持的

2.  O_SYNC在哪写OS上不能正常工作呢??

3.  内核的readwriteFS(文件系统)级别的还是内核(kernel)级别?

(只供参考,有误希望指正)个人觉得是内核级别,因为内核是通过操作VFS来向文件系统写入数据。

4.  文章“innodb_flush_method带来的性能影响“O_DSYNC、和fdatasync效率差很多,这是为什么?

这个连个效率又会受到 innodb_flush_log_at_trx_commit 参数值、设别类型的影响。

 

五、整理自:

 

1.      http://www.orczhou.com/index.php/2009/08/innodb_flush_method-file-io/

2.      http://blog.csdn.net/gua___gua/article/details/44916207

3.      高性能MySQL 3

4.      MySQL 官方文档 5.7

5.      http://www.ibm.com/developerworks/cn/linux/l-cn-read/

6.      系统调用:http://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/index.html

你可能感兴趣的:(mysql)