Linux文件IO(五)IO內核

Linux內核實現I/O主要在三個內核子系統:虛擬文件系統(VFS),頁緩存,和頁回寫。
虛擬文件系統(有時也叫做virtual file switch)是一種Linux內核的文件操作的抽象機制。它允許內核在無需瞭解文件系統類型的情況下,使用文件系統函數和操作文件系統數據。VFS實現這種抽象的方法是使用一種通用文件模型,它是所有Linux文件系統的基礎。基於函數指針和各種面向對象方法,通用文件模型提供了一種Linux內核文件系統必須遵循的框架。它允許VFS對文件系統發起請求。框架提供了鉤子來支持讀,建立鏈接,同步以及其他功能。每種文件系統再使用合適的函數來處理相應操作。
頁緩存是一種在內存中保存最近在磁盤文件系統上訪問過的數據的方式。相對於現在的處理器速度而言,磁盤訪問速度過慢。在內存中保存被請求數據,內核在接下來對相同數據的後續請求可以直接從內存中讀取,儘量避免重複磁盤訪問。頁緩存利用了引用局部性(localityofreference)的一種方法------時間局部性(temporallocality),該方法使剛被訪問資源很可能會在不久後再次被訪問。由於避免了費時的磁盤訪問,內存在第一次訪問時緩存數據的開銷因而得到補償頁緩存是內核尋找文件系統數據的第一目的地。只有緩存中找不到時內核纔會調用存儲子系統從磁盤中讀取數據。,內核使用緩衝區來延遲寫操作。當一個進程發起寫請求,數據被拷貝進一個緩衝區,並將該該緩衝區標記爲”髒”的,這意味着內存中的拷貝要比磁盤上的新。此時,寫請求就可以返回了。如果對同一個數據塊有新的寫請求,緩衝區就更新爲新數據。在該文件其他部分的寫請求則開闢新的緩衝區。
頁回寫是將 那些”髒”緩衝區寫入磁盤,將磁盤文件和內存數據同步。有兩個條件會觸發回寫:
1,當空閒內存小於設定的閾值時,髒的緩衝區就會回寫到磁盤上,被清理的緩衝區可能會被移除,來釋放內存空間;
2,當一個髒的緩衝區壽命超過設定的閾值時,緩衝區被回寫至磁盤。以此來避免數據的不確定性。

I/O調度器和I/O性能
磁盤尋址要理解I/O調度器的工作機制,需要先了解一些背景知識。硬盤基於用柱面(cylinders),磁頭(heads),和扇區(section)幾何尋址方式來獲取數據,這種方式也被成爲CHS尋址。每個硬盤都是由多個盤片組成,每個盤片包括一個磁盤、一個主軸和一個讀寫頭。

I/O調度器實現兩個基本操作:
1,合併(merging)操作是將兩個或多個相鄰的I/O請求的過程合併爲一個。考慮兩次請求,一次讀取5號塊,另一次讀取6和7上的數據。這些請求被合併爲一個對塊5到7的操作。總的I/O吞吐量可能一樣,但是I/O的次數減少了一半。
2,排序(sorting)是選取兩個操作中相對更重要的一個,並按塊號遞增的順序重新安排等待的I/O請求。比如說,I/O操作要求訪問塊52,109,和7,I/O調度這三個請求以7,52,109的順序進行排序.如果一個請求現在要訪問81,它將被插入到訪問52和109的中間。I/O調度器然後按他們在隊列中的順序一次調度:7,然後52,然後81,最後109。

每次讀請求必須返回最新的數據。因此,當請求的數據不在頁緩存中時,讀請求在數據從磁盤讀出前一直會阻塞——這可能是一個相當漫長的操作。我們將這種性能損失稱爲讀延遲(read latency)。一個典型的程序可能在短時期有幾個I/O請求。因爲每個請求都分別進行同步,稍後的請求將依賴於前面請求。當寫操作需要在隊列中插入多個塊時,隊列尾部的塊讀延遲會變得非常嚴重。這種現象就是著名的writes-starving-reads問題。
I/O 調度器使用一種機制避免”餓死”的發生。最簡單的方法就是像2.4內核那樣採用Linux電梯調度法。在該方法中,如果隊列中有一定數量的舊的請求,則停止插入新的請求。這樣整體上可以做到平等對待每個請求,但在讀的時候,卻增加了讀延遲(read latency)。2.6內核丟棄了Linus電梯調度算法,轉而使用了幾種新的調度器算法。
1,Deadline I/O調度器,是爲了解決2.4調度程序及傳統的電梯調度算法的問題。Linus電梯算法維護了一個經過排序的I/O等待列表。隊列首的I/O請求是下一個被調度的。DeadlineI/O調度器保留了這個隊列,爲了進一步改進了原來的調度器,增加了兩個新的隊列:讀FIFO隊列和寫FIFO隊列。FIFO 隊列中的每個請求都設置一個過期時間。讀 FIFO隊列的過期時間設置爲500毫秒,寫隊列則爲5 秒。
2,Anticipatory I/O調度器,Deadline I/O調度器表現很好,但是並不完美。當面對衆多獨立的讀請求時,問題依然會出現-每個讀請求在前一個請求返回後纔會執行,當應用程序得到數據,準備運行並提交了下一個讀請求時, I/O 調度程序已經去處理其他的請求了。這樣導致了每次搜索時都要進行不必要的尋道操作:查找數據,讀數據,返回。
AnticipatoryI/O調度器在Deadline I/O調度器中增加了預測機制,當一個讀操作被提交,anticipatory I/O 調度器在它的終止期限前調度它。不同於Deadline I/O 調度器的是, anticipatory I/O 調度器會等待6毫秒。如果應用程序在6 毫秒內對硬盤同一部分發出另一次讀請求,讀請求立刻被響應, anticipatory I/O 調度器繼續等待。
3,CFQ I/O調度器,儘管在方法上有所區別,但Complete Fair Queuing(CFQ)I/O調度器和上述調度程序的目標是相同的。使用CFQ時,每個進程都有自己的隊列,每個隊列分配一個時間片。I/O調度程序使用輪轉方式訪問並處理隊列中的請求,直到隊列的時間片耗盡或所有的請求都被處理完。後一種情況,CFQ I/O調度器將會空轉一段時間(默認10毫秒),等待當前隊列中新的請求。如果預測成功,I/O調度器避免了查找操作。如果預測無效,調度程序轉而處理下一個進程的隊列。
4,Noop I/O調度器,NoopI/O調度程序是目前最簡單的調度器。無論什麼情況,它都不進行排序操作,只是簡單的合併。它一般用在不需要對請求排隊的特殊設備上。

調度器默認的I/O調度器可以在啓動時可以通過內核參數iosched來指定。有效的選項有as,cfq,deadline,和noop。也可以在運行時針對每個塊設備進行選擇,可以通過修改/sys/block/device/queue/scheduler來完成。讀這個文件可以知道當前的I/O調度器是什麼,把上述有效選項寫入這個文件可以更改I/O調度程序。例如,要設置設備hda的I/O調度程序爲CFQ , 可以使用如下方式:
#echo cfq >/sys/block/hda/queue/scheduler

因爲磁盤I/O相比系統其它部分很慢,同時I/O系統又是現代計算機很重要的一個部分,因此使I/O性能達到最優是非常重要的。減少I/O操作的次數(通過將很多小的操作聚集爲一些大的操作),實現塊對齊的I/O,或者使用用戶空間緩衝,利用高級I/O的優點,如向量I/O,定位I/O和異步I/O,都是系統編程過程中需要經常考慮的重要步驟。爲了使I/O請求能以有利於尋址操作的順序提交,用戶空間程序可以做不同的處理。它們可按照以下方式進行排序:
1,完整路徑:在大部分文件系統採用的佈局算法中,每個目錄裏的文件, 傾向於在磁盤上相鄰分佈。
2,inode編號:使用inode排序比路徑排序更有效 ,通常情況下,inode的順序意味着物理塊的順序。
3,文件的物理塊:通過文件邏輯塊獲得物理塊,然後再排序。。第一步,確定文件中塊的數量。這可以通過stat()調用來完成。其次,對每個邏輯塊,我們用ioctl()調用獲得與它相關的物理塊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章