深入理解Fsync

YY哥發表於2013-08-26

1 介紹

資料庫系統從誕生那天開始,就面對一個很棘手的問題,fsync的效能問題。組提交(group commit)就是為了解決fsync的問題。最近,遇到一個業務反映MySQL建立分割槽表很慢,仔細分析了一下,發現InnoDB在建立表的時候有很多fsync——每個檔案會有4個fsync的呼叫。當然,並不每個fsync的開銷都很大。

 

clip_image002

這裡引出幾個問題:

(1)問題1為什麼fsync開銷相對都比較大?它到底做了什麼?

(2)問題2:細心的人可以發現,第一次open資料檔案後,第二次fsync的時間遠遠小於第1次呼叫fsync的時間,為什麼?

clip_image002[5]

(3)問題3能否最佳化fsync?

來著這些疑問,一起來了解一下fsync。

2 原因分析

我們先透過一個測試程式來學習一下fsync在塊層的基本流程。

2.1 測試程式1

Write page 0

Sleep 5

Fsync

用blktrace跟蹤結果如下:

clip_image004

上半部紅色框內為pwrite在塊層的流程,下半部黃色框內為fsync在塊層流程,中間剛好相差5秒。

4722712為測試檔案的第1個block對應的扇區號,590339(block號) * 8=4722712(扇區號)。

clip_image006

無論是pwrite,還是fsync,主要的開銷都發生IO請求提交給驅動和IO完成之間,也就是說開自裝置驅動。差不多佔了整個系統呼叫的1/2的開銷。

另外,可以看到呼叫fsync時,發生了3次塊層IO,起始扇區分別是19240、19248和19256,物理上3個連續的塊。實際上這3個塊為核心執行緒kjournald寫的日誌,分別描述塊(2405)、資料塊(2406)和提交塊(2407)。為了驗證,不妨看一下這三個塊的實際資料。

塊2405:

clip_image008

#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:

clip_image010

的確是提交塊。

2.2 fsync的實現

既然fsync的開銷很大,就來看看程式碼吧。

函式ext3_sync_file:

clip_image012

函式log_start_commit負責喚醒kjounald核心執行緒,log_wait_commit等待jbd事務提交完成。

clip_image014

從程式碼來看,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

clip_image016

clip_image018

從第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日誌,也就不需要等待事務提交完成。

clip_image020

下面驗證一下該想法。

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修改。

clip_image022

想法被證實了,第2次fsync的時間回到正常水平。

clip_image024

可以看到,第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/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。