ext4文件系統的delalloc選項造成單次寫延遲增加的分析


最近我們的服務進程遇到kill -15后處於Z的狀態,變為了僵屍進程,經過/proc/{thread_id}/stack查看其上線程的棧,發現是卡在了fwrite的過程中,而我們的系統中所有文件系統掛載參數都使用了delalloc參數,懷疑是這個原因:ext4掛載的時候打開了delalloc選項,然后系統在沒有分配磁盤塊的情況下寫寫寫,到page cache被回寫到磁盤時,發現磁盤已經滿了,沒辦法分配新的磁盤塊了,就Hang住了。

 

這篇文章是淘寶內核組的劉崢同學在內部技術論壇上發表的一篇文章,但是由於劉崢同學目前沒有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模式可以簡化為一個單線程追加寫操作的程序,每秒寫入2、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.91

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確實將多個寫操作請求集中到了一起來進行。因此在提供較低平均延遲的情況下,會造成某次寫操作的延遲較大。

通過上面的分析可以看到,目前會受到Ext4的delalloc特性影響的應用必須具備如下條件:
0. Buffer IO
1. 寫操作過程中會涉及磁盤塊的分配,主要是記錄日志這類追加寫操作;
2. 每次寫操作后沒有刷新數據,而是等待系統自動進行回寫;
3. 對延遲有較高要求。

解決方法:關閉delalloc
1. mount -t ext4 -o remount,nodelalloc /${dev} /${mnt};
2. 編輯/etc/fstab中相關mount項,添加nodelalloc掛載參數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM