陶方在《innodb_flush_method帶來的性能影響》中從實驗角度比較了fdatasync,O_DSYNC和O_DIRECT在性能上的差別。本文將試圖從Linux/Unix"文件I/O"(unbuffered I/O)的角度來解釋innodb_flush_method是如何影響MySQL的I/O。【附錄1】html
innodb_flush_log_at_trx_commit參數肯定日誌文件什麼時候write、flush。innodb_flush_method則肯定日誌及數據文件如何write、flush。在Linux下,innodb_flush_method能夠取以下值:fdatasync, O_DSYNC, O_DIRECT,那這三個值分別是如何影響文件寫入的?首先咱們須要先來了解Linux的文件I/O是如何工做的。mysql
先來看看Linux/Unix文件I/O的一個典型例子:(Linux 2.6.24測試,gcc編譯)linux
/** A test about syscall of File I/O Author:supu@TaobaoDBA supu@taobao.com 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操做(將文件緩存刷到磁盤上)。sql
1、Open階段編程
open("test.file",O_WRONLY|O_APPDENT|O_SYNC))
系統調用Open會爲該進程一個文件描述符fd【附錄2】。這裏使用了O_WRONLY|O_APPDENT|O_SYNC打開文件: O_WRONLY表示咱們以"寫"的方式打開,告訴內核咱們須要向文件中寫入數據; O_APPDENT告訴內核以"追加"的方式寫文件; O_DSYNC告訴內核,當向文件寫入數據的時候,只有當數據寫到了磁盤時,寫入操做纔算完成(write才返回成功)。 和O_DSYNC同類的文件標誌,還有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下降文件的順序讀寫的效率。 2、Write階段緩存
write(fd,buf,6)
在使用open打開文件得到文件描述符以後,咱們就能夠調用write函數來寫入數據了,write會根據前面的open參數不一樣,而表現不一樣。安全
3、Flush階段async
fdatasync(fd) == -1
write操做後,咱們還調用了fdatasync來確保文件數據flush到了disk上。fdatasync返回成功後,那麼能夠認爲數據已經寫到了磁盤上。像這樣的flush的函數還有fsync、sync。函數
Fsync和fdatasync的區別等同於O_SYNC和O_DSYNC的區別。 Sync函數表示將文件在OS cache中的數據排入寫隊列,並不確認是否真的寫磁盤了,因此sync並不能夠靠。 忽略文件打開的過程,一般咱們會說「寫文件」有兩個階段,一個是調用write咱們稱爲寫數據階段(實際上是受open的參數影響),調用fsync(或者fdatasync)咱們稱爲flush階段。性能
回到MySQL,參數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()
fdatasync被認爲是安全的,由於在MySQL總會調用fsync來flush數據。使用O_DSYNC是有些風險的,有些OS會忽略該參數O_SYNC。
咱們看到O_DIRECT和fdatasync和很相似,可是它會使用O_DIRECT來打開數據文件。有數據代表,若是是大量隨機寫入操做,O_DIRECT會提高效率。可是順序寫入和讀取效率都會下降。因此使用O_DIRECT須要謹慎。
參考文章:
Unix環境高級編程(第二版) http://rdc.taobao.com/blog/dba/html/296_innodb_flush_method_performance.html http://dev.mysql.com/doc/refman/5.0/en/innodb-parameters.html http://www.ukuug.org/events/linux2001/papers/html/AArcangeli-o_direct.html http://xiaomeng.yo2.cn/articles/buffered-io-and-non-buffered-io.html http://articles.directorym.net/Operating_Systems_System_Calls_and_IO-a894576.html http://www.ibm.com/developerworks/cn/linux/l-cn-read/
http://www.kernel.org/doc/man-pages/online/pages/man2/open.2.html
系統調用:http://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/index.html
【附錄1】文章須要你瞭解什麼是「系統調用「,參考:
http://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/index.html
能夠簡單的理解爲:「系統調用「是在內核之上的一層封裝。由內核直接提供接口,「系統調用」須要陷入內核執行(內核態)。其中fdatasync就是一個系統調用,該系統調用能夠通知OS馬上將OS Cache中的數據Flush到磁盤文件中。
【附錄2】這時候內核會爲該該進程打開的文件分配一個文件描述符,並將該文件描述符返回給該進程。在內核的文件表中新建一個文件項,標記文件狀態、文件當前偏移、以及I節點(v節點)的位置,內核還會打開該文件的I節點(這裏記錄文件的操做的函數指針,例如讀操做、寫操做)。
【附錄3】O_RSYNC個人理解是,對於同一個文件描述符能夠保證讀數據安全。同一個文件描述符包括dup和fcntl函數dup的文件描述符,即共用同一個文件表項。O_RSYNC不是咱們今天關注的,暫時忽略
未解問題:
O_DIRECT在哪些OS(或者FS)上可以正常工做?
O_SYNC在哪寫OS上不能正常工做呢?
內核的read、write是FS級別的仍是內核(kernel)級別?
文章innodb_flush_method帶來的性能影響中O_DSYNC、和fdatasync效率差不少,這是爲何?