轉自 http://blog.tao.ma/?p=58node
這篇文章是淘寶內核組的劉崢同窗在內部技術論壇上發表的一篇文章,可是因爲劉崢同窗目前沒有blog,徵得本人贊成,貼在個人blog上,若是你們喜歡,請去新浪微博關注他。:)性能
日前線上在升級到Ext4文件系統後出現應用寫操做延遲開銷增大的問題。形成這一問題的根源目前已經查明,是因爲Ext4文件系統的一個新特性——Delay Allocation形成的。(後面簡稱delalloc)測試
在詳細分析這一問題以前,先來介紹一下Ext4文件系統的delalloc特性。這一特性簡要歸納起來就是將之前在buffer IO中每次寫操做都會涉及的磁盤塊分配過程推遲到數據回寫時再進行。咱們知道,在進行Buffer Write時,系統的實際操做僅僅是爲這些數據在操做系統內分配內存頁(page cache)並保存這些數據,等待用戶調用fsync等操做強制刷新或者等待系統觸發定時回寫過程。在數據拷貝到page cache這一過程當中,系統會爲這些數據在磁盤上分配對應的磁盤塊。優化
而在使用delalloc後,上面的流程會略有不一樣,在每次Buffer Write時,數據會被保存到page cache中,可是系統並不會爲這些數據分配相應的磁盤塊,僅僅會查詢是否有已經爲這些數據分配過磁盤塊,以便決定後面是否須要爲這些數據分配磁盤塊。在用戶調用fsync或者系統觸發回寫過程時,系統會嘗試爲標記須要分配磁盤塊的這些數據分配磁盤塊。這樣,文件系統能夠爲這些屬於同一個文件的數據分配儘可能連續的磁盤空間,從而優化後續文件的訪問性能(由於傳統機械硬盤順序讀寫的性能要比隨機讀寫好不少)。操作系統
瞭解完delalloc特性的工做過程後,咱們開始分析線上遇到的問題。線上應用的I/O模式能夠簡化爲一個單線程追加寫操做的程序,每秒寫入二、3M數據,寫操做後等待系統自動將數據回寫到磁盤。在使用delalloc後,每次Buffer Write操做,系統都會去查詢數據是否分配了磁盤塊,這一過程須要得到一把讀鎖 (i_data_sem)。因爲這時尚未觸發回寫操做,所以能夠順利獲取i_data_sem,系統完成數據拷貝工做,並返回。因爲僅僅是內存拷貝的過程,因此這一操做速度至關快。當系統開始進行回寫操做時,系統會成批爲數據分配磁盤塊,這一過程一樣須要獲取i_data_sem,而且須要加寫鎖以保證數據的一致性。因爲使用delalloc後,須要分配的磁盤塊比nodelalloc狀況下多不少(nodelalloc狀況下每5秒文件系統會提交日誌觸發回寫;delalloc狀況下,系統會在約每30秒左右觸發一次回寫),所以這一延遲時間較長。若是這時應用程序進行一次Buffer Write,則該操做在嘗試得到i_data_sem時會等待上述磁盤塊分配完成。由此形成寫操做等待很長時間,從而影響應用程序的響應延遲。線程
在上面的分析中已經提到,delalloc是將屢次磁盤塊分配的過程合併到一次中來進行,那麼是否真如預想的那樣,delalloc的平均延遲會小於nodelalloc的狀況呢?咱們使用fio來作以下測試:設置bs=4k,單線程每秒追加寫入5M,程序運行3分鐘,咱們來看一下最後fio對延遲的統計結果:日誌
delalloc:
lat (usec): min=2 , max=193466 , avg= 5.86, stdev=227.91blog
nodelalloc:
lat (usec): min=3 , max=16388 , avg= 7.00, stdev=28.92內存
從上面的統計結果看,寫操做的平均延遲:打開delalloc後爲5.86us,關閉delalloc後爲7.00us;最小延遲delalloc爲2us,nodelalloc爲3us;可是最大延遲delalloc爲193.466ms,nodelalloc下僅爲16.388ms。可見delalloc確實將多個寫操做請求集中到了一塊兒來進行。所以在提供較低平均延遲的狀況下,會形成某次寫操做的延遲較大。rem
經過上面的分析能夠看到,目前會受到Ext4的delalloc特性影響的應用必須具有以下條件:
0. Buffer IO
1. 寫操做過程當中會涉及磁盤塊的分配,主要是記錄日誌這類追加寫操做;
2. 每次寫操做後沒有刷新數據,而是等待系統自動進行回寫;
3. 對延遲有較高要求。
解決方法:關閉delalloc1. mount -t ext4 -o remount,nodelalloc /${dev} /${mnt};2. 編輯/etc/fstab中相關mount項,添加nodelalloc掛載參數