1 介紹
數據庫系統從誕生那天開始,就面對一個很棘手的問題,fsync的性能問題。組提交(group commit)就是為了解決fsync的問題。最近,遇到一個業務反映MySQL創建分區表很慢,仔細分析了一下,發現InnoDB在創建表的時候有很多fsync——每個文件會有4個fsync的調用。當然,並不每個fsync的開銷都很大。
這里引出幾個問題:
(1)問題1:為什么fsync開銷相對都比較大?它到底做了什么?
(2)問題2:細心的人可以發現,第一次open數據文件后,第二次fsync的時間遠遠小於第1次調用fsync的時間,為什么?
(3)問題3:能否優化fsync?
來着這些疑問,一起來了解一下fsync。
2 原因分析
我們先通過一個測試程序來學習一下fsync在塊層的基本流程。
2.1 測試程序1
Write page 0 Sleep 5 Fsync |
用blktrace跟蹤結果如下:
上半部紅色框內為pwrite在塊層的流程,下半部黃色框內為fsync在塊層流程,中間剛好相差5秒。
4722712為測試文件的第1個block對應的扇區號,590339(block號) * 8=4722712(扇區號)。
無論是pwrite,還是fsync,主要的開銷都發生IO請求提交給驅動和IO完成之間,也就是說開自設備驅動。差不多占了整個系統調用的1/2的開銷。
另外,可以看到調用fsync時,發生了3次塊層IO,起始扇區分別是19240、19248和19256,物理上3個連續的塊。實際上這3個塊為內核線程kjournald寫的日志,分別描述塊(2405)、數據塊(2406)和提交塊(2407)。為了驗證,不妨看一下這三個塊的實際數據。
塊2405:
#define JFS_MAGIC_NUMBER 0xc03b3998U #define JFS_DESCRIPTOR_BLOCK 1 #define JFS_COMMIT_BLOCK 2 |
開始的4個字節為JFS_MAGIC_NUMBER,然后是block type:JFS_DESCRIPTOR_BLOCK。
塊2407:
的確是提交塊。
2.2 fsync的實現
既然fsync的開銷很大,就來看看代碼吧。
函數ext3_sync_file:
函數log_start_commit負責喚醒kjounald內核線程,log_wait_commit等待jbd事務提交完成。
從代碼來看,fsync的主要開銷在於調用log_wait_commit后的等待。也就是說fsync要等待kjournald把事務提交完成,才會返回。
到這里,我們已經知道了fsync開銷的主要來源:(1)硬件驅動層的開銷;(2)ext3寫日志。
另外,當log_start_commit返回0時,fsync就不會等待事務提交完成。到這里已經基本可以確認第2次fsync的開銷為什么那么小了——沒有wait事務提交。
下面驗證這一想法。為了方便調試,打開了內核jbd debug日志。
2.3 測試程序2
Write page 0 Fsync Write page 0 Fsync Write page 1 Fsync Write page 2 Fsync |
從第2個紅框的日志來看,第2次fsync時,的確是沒有wait的,所以開銷這么小,而其它3次fsync都調用了log_wait_commit函數。
問題4:第2次fsync為什么不會調用log_wait_commit?
因為掛載文件系統的時候,data=writeback,即寫數據本身不會寫jbd日志。第2次pwrite沒有引起文件擴展,只會修改ext3 inode的i_mtime,而i_mtime只精確到second,也就是說第2次pwrite不會引起inode信息改變,所以,不會生成jbd日志,也就不需要等待事務提交完成。
下面驗證一下該想法。
2.4 測試程序3
Write page 0 Fsync Sleep 1 second Write page 0 Fsync Write page 1 Fsync Write page 2 Fsync |
在第2次pwrite之前,sleep 1秒鍾,保證ext3 inode的i_mtime修改。
想法被證實了,第2次fsync的時間回到正常水平。
可以看到,第2次fsync調用提交了新的事務,並調用了log_wait_commit等待事務完成。
3 優化
如何優化fsync?是個難題。
(1)系統減少對fsync的調用。
(2)ext3日志放在更快的存儲介質,參考http://insights.oetiker.ch/linux/external-journal-on-ssd/
作者:YY哥
出處:http://www.cnblogs.com/hustcat/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。