1. 程式人生 > >如何讓linux伺服器磁碟io效能翻倍

如何讓linux伺服器磁碟io效能翻倍

這一期我們來看一下有哪些辦法可以減少linux下的檔案碎片。主要是針對磁碟長期滿負荷運轉的使用場景(例如http代理伺服器);另外有一個小技巧,針對網際網路圖片伺服器,可以將io效能提升數倍。如果為伺服器訂製一個專用檔案系統,可以完全解決檔案碎片的問題,將磁碟io的效能發揮至極限。對於我們的代理伺服器,相當於把io效能提升到3-5倍。

在現有檔案系統下進行優化linux核心和各個檔案系統採用了幾個優化方案來提升磁碟訪問速度。但這些優化方案需要在我們的伺服器設計中進行配合才能得到充分發揮。

檔案系統快取linux核心會將大部分空閒記憶體交給虛擬檔案系統,來作為檔案快取,叫做page cache
。在記憶體不足時,這部分記憶體會採用lru演算法進行淘汰。
通過free命令檢視記憶體,顯示為cached的部分就是檔案快取了。

如果能找到當前使用場景下,檔案被訪問的統計特徵,針對性的寫一個淘汰演算法,可以大幅提升檔案快取的命中率。對於http正向代理來說,一個好的淘汰演算法可以用1GB記憶體達到lru演算法100GB記憶體的快取效果。如果不打算寫一個新的淘汰演算法,一般不需要在應用層再搭一個檔案cache程式來做快取。

最小分配

最小分配的副作用是會浪費一些磁碟空間(分配了但是又沒有使用)

如果當前使用場景下小檔案很多,把預分配改大就會浪費很多磁碟空間,所以這個數值要根據當前使用場景來設定。

似乎要直接改原始碼才能生效,不太記得了,09年的時候改的,有興趣的同學自己google吧。


io訪問排程

如何針對性優化:io訪問排程能大幅提升io效能,前提是應用層同時發起了足夠的io訪問供linux去排程。怎樣才能從應用層同時向核心發起多個io訪問呢?方案一是用aio_read非同步發起多個檔案讀寫請求。

小提示:將檔案控制代碼設定為非阻塞時,程序還是會睡眠等待磁碟io,非阻塞對於檔案讀寫是不生效的。在正常情況下,讀檔案只會引入十幾毫秒睡眠,所以不太明顯;而在磁碟io極大時,讀檔案會引起十秒以上的程序睡眠。詳見核心原始碼do_generic_file_read會呼叫lock_page_killable

進入睡眠,但是不會判斷控制代碼的非阻塞標誌。

預讀取linux核心可以預測我們“將來的讀請求”並提前將資料讀取出來。通過預讀取可以減少讀io的次數,並且減小讀請求的延時。

當檔案擴大,需要分配磁碟空間時,可以不立即進行分配,而是暫存在記憶體中,將多次分配磁碟空間的請求聚合在一起後,再進行一次性分配。

延遲分配的副作用有幾個:如果應用程式每次寫資料後都通過fsync等介面進行強制重新整理,延遲分配將不起作用延遲分配有可能間歇性引入一個較大的磁碟IO延時(因為要一次性向磁碟寫入較多資料)

如何針對性優化:

“讓每個目錄下的檔案連續儲存”是一個極有價值的功能。假設一個網頁上有10張圖片,這10張圖片雖然存在10個檔案中,但其實是幾乎同時被使用者訪問的。如果能讓這10張圖片儲存在連續的磁碟空間中,就能把io效能提升10倍(一次尋道就可以讀10個檔案了)傳統的做法是通過拼接圖片來將這10張圖片合併到一張大圖中,再由前端將大圖切成10張小圖。有了e4defrag後,可以將需連續訪問的檔案放在同一個資料夾下,再定期使用e4defrag進行磁碟整理。

實現自己的檔案系統我們曾經寫過一款專用檔案系統,針對代理伺服器,將磁碟io效能提升到3-5倍。在大部分伺服器上,不需要支援“修改檔案”這個功能。一旦檔案建立好,就不能再做修改操作,只支援讀取和刪除。在這個前提下,我們可以消滅所有檔案碎片,把磁碟io效率提升到理論極限。

大於16MB的檔案,伺服器建立檔案時告訴檔案系統分配16MB磁碟空間。後續每次擴大檔案大小時,要麼是16MB,要麼就是檔案終結。不允許在檔案未終結的情況下分配非16MB的空間。讀寫檔案時,每次讀寫16MB或者直到檔案末尾。

在我們的檔案系統中,小檔案完全無碎片,一次尋道就能搞定一個檔案,達到了理論上最佳的效能。大檔案每次磁頭定位讀寫16MB,效能沒有達到100%,但已經相當好了。有一個公式可以衡量磁碟io的效率:磁碟利用率 傳輸時間/(平均尋道時間+傳輸時間)對我們當時採用的磁碟來說(1T 7200sata)16MB連續讀寫已經可以達到98%以上的磁碟利用率。