春天來了,除了工作學習,大家也要註意鍛煉身體,多出去運動運動。上周末在元大都遺址公園海棠花溪拍的海棠花。進入正題。O_DIRECT和O_SYNC是系統調用open的flag參數。通過指定open的flag參數,以特定的文件描述符打開某一文件。這兩個flag會對寫盤的性能有很大的影響,因此對這兩個fl... ...
春天來了,除了工作學習,大家也要註意鍛煉身體,多出去運動運動。
上周末在元大都遺址公園海棠花溪拍的海棠花。
進入正題。
O_DIRECT和O_SYNC是系統調用open的flag參數。通過指定open的flag參數,以特定的文件描述符打開某一文件。
這兩個flag會對寫盤的性能有很大的影響,因此對這兩個flag做一些詳細的瞭解。
先看一個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
#include int fdatasync(int fd);函數返回值:
- 0: success
- -1: error
#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文件系統上的新創建文件,比較寫入時間。 對比結果: 從結果中可以得到的結論:
- 採用O_SYNC標誌(或者頻繁調用fsync(), fdatasync()或sync())對性能影響極大。
- 性能下降的直接表現為運行總用時大為增加:在緩衝區為1位元組的情況下,運行時間相差1000多倍。
- 以O_SYNC標誌執行寫操作時運行總用時和CPU時間之間的巨大差異(1030 - 98.8),原因是系統在每個緩衝區中將數據向磁碟傳遞時會把程式阻塞起來。
三,IO緩衝層次關係
先總結一下stdio函數庫和內核採用的緩衝這兩級緩衝,然後用圖說明兩層緩衝機制和各種緩衝類型的控制機制。- 首先,通過stdio庫將用戶數據傳遞到stdio緩衝區,該緩衝區位於用戶態記憶體區。
- 當緩衝區填滿,stdio庫會調用write()系統調用,將數據傳遞到內核高速緩衝區,該緩衝區位於內核態記憶體區。
- 最終,內核發起磁碟操作。
上圖中,左側虛線方框中為可於任何時刻顯式強制刷新各類緩衝區的調用。 右側所示為促使刷新自動化的調用:通過禁用stdio的緩衝,和在文件輸出類的系統調用中啟用同步,從而使每個write()調用立刻刷新到磁碟。
四,小結
輸入輸出數據的緩衝由內核和stdio庫完成。有時可能希望阻止緩衝,但這需要瞭解其對應用程式性能的影響。 可以使用各種系統調用和庫函數來控制內核和stdio緩衝,並執行一次性的緩衝區刷新。 在Linux環境下,open()所特有的O_DIRECT標識允許特定應用跳過緩衝區高速緩存。雖然題目還是UNIX高級環境變成(xx),但是打算把所閱讀和參考的書換成《Linux/UNIX系統編程手冊》。感覺這本書內容更新一點。
工作很忙,周末大部分時間都在外面活動,跑步拍照,雖然只是簡單的讀書這一篇也是拖了又拖才敲完。
參考:
《Linux/UNIX系統編程手冊(上冊)》