UNIX高級環境編程(14)文件IO - O_DIRECT和O_SYNC詳解 < 海棠花溪 >

春天來了,除了工做學習,你們也要注意鍛鍊身體,多出去運動運動。 數據庫

上週末在元大都遺址公園海棠花溪拍的海棠花。編程

DSC 2639 01

 

進入正題。緩存

O_DIRECT和O_SYNC是系統調用open的flag參數。經過指定open的flag參數,以特定的文件描述符打開某一文件。安全

這兩個flag會對寫盤的性能有很大的影響,所以對這兩個flag作一些詳細的瞭解。async

先看一個open函數的使用例子.函數

/* Open new or existing file for reading and wrting,
    sync io and no buffer io; file permissions read+
    write for owner, nothing for all others */
fd = open("myfile", O_RDWR | O_CREAT | O_SYNC | O_DIRECT, S_IRUSR | S_IWUSR);
if (fd == -1)
    errExit("open");
O_DIRECT: 無緩衝的輸入、輸出。
O_SYNC:以同步IO方式打開文件。
下面對這兩個flag作一些詳細的說明。
 

一,O_DIRECT,繞過緩衝區高速緩存,直接IO

直接IO:Linux容許應用程序在執行磁盤IO時繞過緩衝區高速緩存,從用戶空間直接將數據傳遞到文件或磁盤設備,稱爲直接IO(direct IO)或者裸IO(raw IO)。
應用場景:數據庫系統,其高速緩存和IO優化機制均自成一體,無需內核消耗CPU時間和內存去完成相同的任務。
使用直接IO的弊端:可能會大大下降性能,內核對緩衝區告訴緩存作了很多優化,包括:按順序預讀取,在成簇磁盤塊上執行IO,容許訪問同一文件的多個進程共享高速緩存的緩衝區。
使用方法:在調用open函數打開文件或設備時指定O_DIRECT標誌。
注意可能發生的不一致性:若一進程以O_DIRECT標誌打開某文件,而另外一進程以普通(即便用了高速緩存緩衝區)打開同一文件,則由直接IO所讀寫的數據與緩衝區高速緩存中內容之間不存在一致性,應儘可能避免這一場景。
 
使用直接IO須要遵照的一些限制:
  • 用於傳遞數據的緩衝區,其內存邊界必須對齊爲塊大小的整數倍
  • 數據傳輸的開始點,即文件和設備的偏移量,必須是塊大小的整數倍
  • 待傳遞數據的長度必須是塊大小的整數倍。

不遵照上述任一限制均將致使EINVAL錯誤。性能

 

二,O_SYNC,以同步方式寫入文件

功能:強制刷新內核緩衝區到輸出文件。這是有必要的,由於爲了數據安全,須要確保將數據真正寫入磁盤或者磁盤的硬件告訴緩存中。學習

咱們先熟悉一下同步IO相關定義和系統調用。優化

同步IO數據完整性和同步IO文件完整性

同步IO的定義:某一IO操做,要麼已成功完成到磁盤的數據傳遞,要麼被診斷爲不成功。
SUSv3定義的兩種同步IO完成類型(此處用英文,由於譯者也忍無可忍用了原文…)
  • synchronized IO data integrity completion:確保針對文件的一次更新傳遞了足夠的信息(部分文件元數據)到磁盤,以便於以後對數據的獲取。
  • synchronized IO file integrity completion:確保針對文件的一次更新傳遞了全部的信息(全部文件元數據)到磁盤,即便有些在後續對文件數據的操做並不須要。

用於控制文件IO內核緩衝的系統調用

1 fsync線程

做用:fsync()系統調用將使緩衝數據和fd相關的全部元數據都刷新到磁盤上。調用fsync會強制使文件處於Synchronized IO file integrity completion狀態。
函數聲明:
#include
int fsync(int fd);

函數返回值:
  • 0: success
  • -1: error
返回時間:僅在對磁盤設備(或者至少是其高速緩存)的傳遞完成後,fsync()調用纔會返回。
 
2 fdatasync
做用:fdatasync()系統調用的做用相似fsync(),只是強制文件處於synchronized IO data integrity compeletion狀態。
函數聲明:
#include
int fdatasync(int fd);

函數返回值:
  • 0: success
  • -1: error
與fsync的區別:fdatasync()可能會減小磁盤操做的次數,由fsync()調用請求的兩次變成一次。例如,修改了文件的數據,而文件大小不變,那麼調用fdatasync調用請求只強制進行了數據更新,相比之下,fsync()調用會強制將元數據傳遞到磁盤上,而元數據和文件數據一般駐留在磁盤的不一樣區域,更新這些數據須要反覆在整個磁盤上執行尋道操做。
 
3 sync系統調用
做用:sync()系統調用會使包含更新文件信息的全部內核緩衝區(即數據塊、指針塊、元數據等)刷新到磁盤上。
函數聲明:
#include
void sync(void);

細節:若內容發生變化的內核緩衝區在30s內未經顯式方式同步到磁盤上,則一條長期運行的內核線程會確保將其刷新到磁盤上。這一作法是爲了規避緩衝區與相關磁盤文件內容長期處於不一致狀態。
 
4 使全部寫入同步:O_SYNC
調用open()函數時,如制定O_SYNC標誌,則會使全部後續輸出同步。
fd = open(pathname, O_WRONLY | O_SYNC);

做用:調用open後,每一個write調用會自動將文件數據和元數據刷新到磁盤上,即按照Synchronized IO file integrity completion的要求執行寫操做。
 
5 有無O_SYNC性能對比
場景:將一百萬字節寫入一個ext2文件系統上的新建立文件,比較寫入時間。
對比結果:
NewImage
從結果中能夠獲得的結論:
  • 採用O_SYNC標誌(或者頻繁調用fsync(), fdatasync()或sync())對性能影響極大。
  • 性能降低的直接表現爲運行總用時大爲增長:在緩衝區爲1字節的狀況下,運行時間相差1000多倍。
  • 以O_SYNC標誌執行寫操做時運行總用時和CPU時間之間的巨大差別(1030 - 98.8),緣由是系統在每一個緩衝區中將數據向磁盤傳遞時會把程序阻塞起來。
 

 三,IO緩衝層次關係

先總結一下stdio函數庫和內核採用的緩衝這兩級緩衝,而後用圖說明兩層緩衝機制和各類緩衝類型的控制機制。
  • 首先,經過stdio庫將用戶數據傳遞到stdio緩衝區,該緩衝區位於用戶態內存區。
  • 當緩衝區填滿,stdio庫會調用write()系統調用,將數據傳遞到內核高速緩衝區,該緩衝區位於內核態內存區。
  • 最終,內核發起磁盤操做。
該層次結構以下圖所示
 
NewImage

 

上圖中,左側虛線方框中爲可於任什麼時候刻顯式強制刷新各種緩衝區的調用。
右側所示爲促使刷新自動化的調用:經過禁用stdio的緩衝,和在文件輸出類的系統調用中啓用同步,從而使每一個write()調用馬上刷新到磁盤。
 

四,小結

輸入輸出數據的緩衝由內核和stdio庫完成。有時可能但願阻止緩衝,但這須要瞭解其對應用程序性能的影響。
可使用各類系統調用和庫函數來控制內核和stdio緩衝,並執行一次性的緩衝區刷新。
在Linux環境下,open()所特有的O_DIRECT標識容許特定應用跳過緩衝區高速緩存。
 
 

雖然題目仍是UNIX高級環境變成(xx),可是打算把所閱讀和參考的書換成《Linux/UNIX系統編程手冊》。感受這本書內容更新一點。

工做很忙,週末大部分時間都在外面活動,跑步拍照,雖然只是簡單的讀書這一篇也是拖了又拖才敲完。

 

參考:

《Linux/UNIX系統編程手冊(上冊)》  

相關文章
相關標籤/搜索