在很多io場景中,我們經常需要確保資料已經安全的寫到磁碟上,以便在系統宕機重啟之後還能讀到這些資料。但是我們都知道,linux系統的io路徑還是很複雜的,分為很多層,每一層都可能會有buffer來加速io讀寫。同時,使用者態的應用程式和庫函式也可能擁有自己的buffer,這又給io路徑增加了一些複雜性。可見,要想保證資料安全的寫到磁碟上,並不是簡單調乙個write/fwrite就可以搞定的。
那麼要怎麼做呢?很多人會想到很多辦法,比如:fflush()、fsync()、fdatasync()、sync()、open()使用o_direct或o_sync標誌等。嗯,這些手段(或者某些組合)的確可以保證資料安全的持久化,那麼它們之間有什麼區別呢?fflush()和fsync()有啥區別?o_direct是啥意思,它可以保證資料安全的持久化嗎?o_direct和o_sync區別什麼?o_sync和fsync()呢?fsync能完成msync的功能嗎?本文將試圖理解、解釋這些概念的作用和區別。
linux io
所謂一圖勝千言,為了解析清楚這些概念的區別,我特意畫了一張圖,仔細看,應該可以清晰的看出它們的作用和區別。
這裡重點說一下o_direct和o_sync,首先要明確的是,o_direct只是說資料不會經過page cache(一般用在使用者態自己管理buffer)而是直接提交給塊裝置層,但是不會同步等待資料安全寫入磁碟之後才返回(比如資料可能還在塊層排隊或者在磁碟自己的cache中)。而o_sync標誌,雖然資料還是會寫page cache,但是此時會採用write through的策略,並同步等待資料安全寫入磁碟後才會返回。因此如果同時使用o_direct和o_sync,則表示資料不會經過page cache並同步等待資料安全寫入磁碟才返回,當然這樣io的效能會非常低下。
由於o_direct會bypass page cache,因此如果有另乙個程序使用普通的方式讀檔案,有可能會出現資料不一致的現象,這個也需要注意。
為了做一下輔助說明,此處我貼一下我**過程中看過的一些資料。首先是引用open系統呼叫:
相關引數的說明:
以及innodb相關的文件:
fsync和fdatasync的區別:
其實還有一種io模式,就是dax(direct access ),是不是看上去和o_direct很像。這種模式需要filesystem和block driver都支援才可以,一般主要用在non volatile memory上,本質上也是繞過page cache直接操作裝置。dax本文先不做深入**,後面我會自己寫乙個支援dax模式的ramdisk塊裝置驅動,然後格式化為ext4檔案系統並-o dax模式掛載,再來詳細研究dax的io路徑。
最後附上linux在常見場景下的io路徑跟蹤:
Linux 系統掛載資料盤
適用系統 linux redhat centos,debian,ubuntu linux的雲伺服器資料盤未做分割槽和格式化,可以根據以下步驟進行分割槽以及格式化操作。下面的操作將會把資料盤劃分為乙個分割槽來使用。1 檢視資料盤 在沒有分割槽和格式化資料盤之前,使用 df h 命令,是無法看到資料盤的...
Linux 系統掛載資料盤
適用系統 linux redhat centos,debian,ubuntu linux的雲伺服器資料盤未做分割槽和格式化,可以根據以下步驟進行分割槽以及格式化操作。下面的操作將會把資料盤劃分為乙個分割槽來使用。1 檢視資料盤 在沒有分割槽和格式化資料盤之前,使用 df h 命令,是無法看到資料盤的...
Linux 系統掛載資料盤
適用系統 linux redhat centos,debian,ubuntu linux的雲伺服器資料盤未做分割槽和格式化,可以根據以下步驟進行分割槽以及格式化操作。下面的操作將會把資料盤劃分為乙個分割槽來使用。1 檢視資料盤 在沒有分割槽和格式化資料盤之前,使用 df h 命令,是無法看到資料盤的...