最近在測試種發現程序里調用fsync刷文件到磁盤時,開銷只有幾百微秒,於是對fsync相關機制進行了一番調查。
磁盤(或RAID卡)自身通常會有硬件緩存機制,對於寫操作,有write back和write through兩種機制,前者將數據寫至緩存就會返回,而后者則會將數據寫到磁盤介質上。當使用write back機制時,fsync刷的文件數據可能只是寫到磁盤緩存就返回了,導致從應用看來,寫數據到磁盤的開銷很小(實際上並未執行磁盤寫操作);所以,使用write back機制時,即使上層應用顯式fsync成功,數據也是可能丟失的,比如緩存里的數據還未刷到磁盤時掉電了,有些存儲設備會使用備用電池(BBU,Battery backup unit)來避免掉電時緩存數據丟失。
如果要保證fsync調用成功后,數據一定持久化到磁盤,則要使用內核的write barrier機制。該機制通過在IO操作之前和之后顯式刷新存儲設備的緩存來達到目的,在文件系統mount的時候可以指定是否開啟barrier機制,ext4默認啟用barrier機制。
對於內存映射(mmap)的文件數據,msync的功能與fsync類似,將內存映射數據刷到磁盤,msync使用時有3個標志。
- MS_SYNC,數據同步刷到磁盤后返回(可能只是寫到磁盤緩存)
- MS_ASYNC, 對於更新的文件數據會提交IO操作到底層,但不會等IO操作執行完成,而是立即返回
- MS_INVALIDATE,更新文件對應的其它映射數據(如內存區域M1、M2都映射了文件F的數據,如果在msync M1的時候指定了該標記,則M2內存區域里的數據也會被更新)。
要想映射內存msync后被持久化到磁盤,需要使用MS_SYNC標記;而msync調用后數據是否一定持久化,則要看存儲設備使用的緩存機制以及內核write barrier是否啟用。