共計 2315 個字符,預計需要花費 6 分鐘才能閱讀完成。
這篇“Linux 塊設備中的 IO 路徑及調度策略是什么”文章的知識點大部分人都不太理解,所以丸趣 TV 小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Linux 塊設備中的 IO 路徑及調度策略是什么”文章吧。
當文件系統通過 submit_bio 提交 IO 之后,請求就進入了通用塊層。通用塊層會對 IO 進行一些預處理的動作,其目的是為了保證請求能夠更加合理的發送到底層的磁盤設備,盡量保證性能。這里面比較重要的就是 IO 調度模塊。大家可能都聽說過 CFQ,除此之前還有 DeadLine 和 Noop 等,這些都是磁盤的調度算法。其中 CFQ 調度算法用的最多。
如果忽略塊設備的層疊結構和各種映射,簡化的結構大概有 3 層,如圖 1 所示。這里的 3 層并非都是軟件,還包含硬件。通用塊層就不用多說了,這里主要完成 IO 的合并和調度等操作。其下是驅動層,驅動層是硬件的驅動程序,用于將 IO 請求轉換為對硬件寄存器的操作(注:不同的塊設備又有差異,必然 iSCSI 設備是不會有寄存器操作的)。物理設備不同該驅動層的程序就不同,比如對于 SAS 直連的磁盤,該驅動層的程序就是 SAS 驅動,而如果是 FC-HBA 卡連接的 FC-SAN,那么這個驅動層就是 FC 驅動(比如 Qlogic 的驅動)。
圖 1 塊設備分層
最下面一層是設備層,設備層通常是一個硬件設備。這里的硬件種類繁多,比如 SAS 卡、SATA 卡、FC-HBA 卡或者 iSCSI-HBA 卡等等。但有的時候又可能并不是硬件設備,比如對于 iSCSI 來說,該層可能是通過軟件模擬的一個設備層,而其請求則是通過網卡發送到目標器端。
主要數據結構及流程
絕大多數程序都是由數據結構和算法 2 部分內容組成的,數據結構相當于程序的骨架,而算法則是程序的筋和肉。通過算法將數據結構關聯起來,從而形成一個完整的整體。人類認識問題的規律是從具體到抽象,從簡單到復雜,因此我們先從數據結構開始。理解了數據關鍵的數據結構,那我們就能更加容易的理解塊設備 IO 的整個邏輯。
在塊設備 IO 中最為關鍵的數據結構是 request_queue,也就是請求隊列。該數據結構的簡圖如圖 2 所示,這個數據結構本身非常復雜,我們這里進行了簡化,只保留了部分關鍵的成員。如圖彩色部分是 2 個函數指針,分別用于接收請求和處理請求。
圖 2 請求隊列數據結構
為了便于理解,我們這里舉一個例子。以 NBD 塊設備為例,在塊設備初始化的時候 make_request_fn 被初始化為 blk_queue_bio,request_fn 被初始化為 do_nbd_request。對于 SCSI 塊設備而言,request_fn 會被初始化為 scsi_request_fn。
有了上面數據結構的知識及關鍵成員初始化的結果,接下來我們就可以分析一下塊設備的整個流程的細節。塊設備請求的入口是 submit_bio,經過簡單的檢查后調用
由上述代碼可以看出 IO 處理的入口函數其實是函數指針 make_request_fn,而我們知道該指針實際上是函數 blk_queue_bio。因此塊設備的請求會由 blk_queue_bio 函數進行處理。
磁盤調度策略
Linux 內核在設計磁盤的調度策略時提供了極大的靈活性。磁盤的調度策略以插件的注冊到內核當中,也就是用戶可以自由的選擇磁盤的調度策略。
調度算法的思想其實非常簡單,主要是通過對 IO 的排序、合并和批量處理來優化磁盤尋道和請求的處理時間。這里值得說明的目前的調度算法其實更多的是針對機械磁盤,因為機械磁盤磁頭定位耗時占整個 IO 處理時間的很大比例。當然對于 SSD 磁盤,調度算法也有一定的幫助,這就需要針對 IO 的特性具體來看了。
圖 3 調度策略結構體
磁盤調度策略的結構體定義如圖 3 所示,各個變量的含義也是比較明確,本文不再贅述。本文主要看一下 其中 elevator_ops 類型的變量 ops,這個變量是調度策略具體的功能實現,任何調度算法都要實現其中某些函數。
調度策略的實現就是通過這些回調函數完成的。為了理解調度策略的函數集具體做哪些事情,本文整理了一個表格,我們先從整體上看一下每個函數具體做了哪些事情。對于調度策略來說,這里的函數并非每個都要實現,下表中只有帶 * 的才是必須要實現的函數。
簡而言之,上述回調函數的功能就是判斷請求是否可以被合并、執行合并和請求下發等等操作。上述回調函數比較多,而且使用場景也比較復雜,具體使用分散在調度器的很多流程中。因此,我們很難一下子介紹清楚所有的場景。為了更加直觀的理解上述回調函數的作用,我們以 Deadline 調度策略為例進行簡單的介紹。
如圖 4 是 Deadline 初始化的回調函數,從圖中可以看出這里并沒有初始化所有的回調函數,而只初始化了 16 個回調函數中的 9 個。
圖 4 Deadline 回調函數
我們具體分析一下函數的調用場景,前文我們介紹到 elevator_merge_fn 函數用于查詢可以與 bio 合并的請求。如圖 5 所示為整個調用棧,入口為 blk_queue_bio,這個函數我們之前介紹過,它就是調度程序的入口。該函數調用 elv_merge 用于查找是否有可以合并的請求,并返回。而 elv_merge 函數調用的正式 Deadline 調度器提供的回調函數。完成判斷后,該函數會根據實際情況返回請求 (或者沒有找到,不返回) 和可合并的方向(例如向前合并,向后合并等),后續流程就是進行具體的合并操作了。
圖 5 函數調用棧
以上就是關于“Linux 塊設備中的 IO 路徑及調度策略是什么”這篇文章的內容,相信大家都有了一定的了解,希望丸趣 TV 小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注丸趣 TV 行業資訊頻道。