同CPU,、內(nèi)存一樣,,文件系統(tǒng)和磁盤I/O,也是Linux操作系統(tǒng)最核心的功能,。
磁盤為系統(tǒng)提供了最基本的持久化存儲,。
文件系統(tǒng)則在磁盤基礎(chǔ)上,提供了一個用來管理文件的樹狀結(jié)構(gòu),。
文件系統(tǒng)
1. 索引節(jié)點和目錄項
Linux中的一切都由統(tǒng)一的文件系統(tǒng)來管理,,包括普通的文件和目錄,以及塊設(shè)備,、套接字,、管道等。Linux文件系統(tǒng)為每個文件都分配了兩個數(shù)據(jù)結(jié)構(gòu),,索引節(jié)點(index node)和目錄項(directory entry),,主要用來記錄文件的元信息和目錄結(jié)構(gòu),。
索引節(jié)點,簡稱為 inode,,用來記錄文件的元數(shù)據(jù),,比如inode編號、文件大小,、訪問權(quán)限,、修改日期、數(shù)據(jù)的位置等,。索引節(jié)點和文件一一對應(yīng),,它跟文件內(nèi)容一樣會被持久化到磁盤,所以,,索引節(jié)點同樣占磁盤,。
目錄項,簡稱為dentry,,用來記錄的文件的名字,、索引節(jié)點指針以及與其他目錄項的關(guān)聯(lián)關(guān)系。多個關(guān)聯(lián)的目錄項,,就構(gòu)成了文件系統(tǒng)的目錄結(jié)構(gòu),,它是由內(nèi)核維護的一個內(nèi)存數(shù)據(jù)結(jié)構(gòu),通常也被稱為目錄項緩存,。
換句話說,,索引節(jié)點是每個文件的唯一標志,目錄項維護的是文件系統(tǒng)的樹狀結(jié)構(gòu),。目錄項和索引節(jié)點的關(guān)系是多對一,,或者可理解為一個文件多個別名。舉個例子,,通過硬鏈接為文件創(chuàng)建的別名,,就會對應(yīng)不同目錄項,這些目錄項本質(zhì)上是連接同一個文件,,所以索引節(jié)點相同,。
更具體地說,文件數(shù)據(jù)是怎么存儲的,,是直接保存到磁盤的,?實際上磁盤讀寫的最小單位是扇區(qū),扇區(qū)只有512B大小,,如果每次讀寫這么小的單位,,效率一定很低。所以,文件系統(tǒng)又把連續(xù)的扇區(qū)組成邏輯塊,,再以邏輯塊為最小單元去管理數(shù)據(jù),。常見的邏輯塊大小是4KB,即連續(xù)的8個扇區(qū),。下面展示一張示意圖:
這里需要注意兩點:
第一,,目錄項本身在內(nèi)存中,索引節(jié)點在磁盤中,。前面的 Buffer 和 Cache 原理中提到,,為了協(xié)調(diào)慢速磁盤和快速CPU之間的性能差異,文件內(nèi)容會緩存到頁緩存 Cache中,。索引節(jié)點自然也會緩存到內(nèi)存中,,增加速文件訪問。
第二,,磁盤在執(zhí)行文件系統(tǒng)格式化時,,會被分成三個存儲區(qū)域,超級塊,、索引節(jié)點區(qū) 和 數(shù)據(jù)塊區(qū),。其中,超級塊存儲整個文件系統(tǒng)狀態(tài),;索引節(jié)點區(qū)存儲索引節(jié)點,;數(shù)據(jù)塊區(qū),存儲文件數(shù)據(jù),。
2. 虛擬文件系統(tǒng)
目錄項,、索引節(jié)點、超級塊,、邏輯塊構(gòu)成Linux文件系統(tǒng)四大基本要素,。不過,為了支持各種不同的文件系統(tǒng),,Linux內(nèi)核在用戶進程和文件系統(tǒng)中間,引入了一個抽象層,,即虛擬文件系統(tǒng)VFS,。VFS定義了一套所有文件系統(tǒng)都支持的數(shù)據(jù)結(jié)構(gòu)和標準接口。這樣,,用戶層和內(nèi)核其他子系統(tǒng)都只需要跟 VFS 提供的統(tǒng)一接口交互就可以了,,不需要關(guān)心底層各種文件系統(tǒng)的實現(xiàn)細節(jié)。下圖很好展示了Linux文件系統(tǒng)的架構(gòu)圖,,能更好的幫助理解系統(tǒng)調(diào)用,、VFS、緩存、文件系統(tǒng)以及塊存儲之間的關(guān)系:
從圖中可以看到,,在VFS下面Linux可以支持各種文件系統(tǒng),,按照存儲位置的不同,可以分為三類:
基于磁盤的文件系統(tǒng),,也就是把數(shù)據(jù)直接存儲到計算機本地掛載的磁盤中,。如 EXT4、XFS,、OverlayFS等,。
基于內(nèi)存的文件系統(tǒng),也就是虛擬文件系統(tǒng),,不需要磁盤分配任何存儲空間,,只占用內(nèi)存。如 /proc 文件系統(tǒng),、/sys 文件系統(tǒng)(主要向用戶空間導出層次化的內(nèi)核對象),。
網(wǎng)絡(luò)文件系統(tǒng),用來訪問其他計算機數(shù)據(jù)的文件系統(tǒng),,如 NFS,、SMB、iSCSI等,。
這些文件系統(tǒng),,要先掛載到 VFS 目錄樹中的子目錄(掛載點),然后才能訪問其中文件,。比如安裝系統(tǒng)時,,要先掛在一個根目錄( / ),在根目錄下,,再把其他文件系統(tǒng)掛在進來,。
3. 文件系統(tǒng)I/O
把文件掛到掛載點后,就能通過它去訪問它管理的文件了,。VFS提供的訪問文件的標準接口,,以系統(tǒng)調(diào)用的方式提供給應(yīng)用程序使用。比如,,cat命令,,相繼調(diào)用 open()、read(),、write(),。文件讀寫方式的各種差異,也導致I/O 的分類多種多樣,。常見的有,,緩沖與非緩沖I/O,、直接與非直接I/O、阻塞與非阻塞I/O,、同步與異步I/O等,。下面詳細解釋下這四種 I/O分類:
第一種,根據(jù)是否利用標準庫緩存,,可以把文件I/O 分為 緩沖I/O 和 非緩沖I/O,。這里的“緩沖”,其實指的是標準庫內(nèi)部實現(xiàn)的緩存,。例如,,很多程序遇到換行時才真正輸出,換行前的內(nèi)容,,就是被標準庫暫時緩存起來,。因此,緩沖I/O 指的是利用標準庫緩存來加速文件的訪問,,在標準庫內(nèi)部再通過系統(tǒng)調(diào)用訪問文件,;非緩沖I/O 指的是直接通過系統(tǒng)調(diào)用訪問文件,而不通過標準庫緩存,。無論是緩沖還是非緩沖 I/O,,最后都是通過系統(tǒng)調(diào)用訪問文件。而根據(jù)前面內(nèi)容,,系統(tǒng)調(diào)用后,,還通過頁緩存,來減少磁盤I/O操作,。
第二種,,根據(jù)是否利用操作系統(tǒng)的頁緩存,可以把文件I/O 分為直接I/O 和 非直接I/O,。想要實現(xiàn)直接I/O,,需要在系統(tǒng)調(diào)用中指定標志 O_DIRECT,如果不指定,,默認是非直接I/O,。不過注意,這里的直接,、非直接I/O,,其實最終還是和文件系統(tǒng)交互。如果實在數(shù)據(jù)庫等場景中,,還會看到,跳過文件系統(tǒng)讀寫磁盤的情況,,即裸I/O,。
第三種,根據(jù)應(yīng)用程序是否阻塞自身運行,可以把文件I/O 分為阻塞I/O 和 非阻塞I/O,。在應(yīng)用程序執(zhí)行I/O 操作后,,如果沒獲得響應(yīng),就阻塞當前線程,,自然不能執(zhí)行其他任務(wù),,這是阻塞I/O;如果沒獲得響應(yīng),,卻不阻塞當前線程,,繼續(xù)執(zhí)行其他任務(wù),隨后通過輪詢或者時間通知的形式,,獲得之前調(diào)用的結(jié)果,。比如,訪問管道或者網(wǎng)絡(luò)套接字時,,設(shè)置 O_NONBLOCK 標志,,表示非阻塞方式訪問,若不做任何設(shè)置,,默認就是阻塞方式訪問,。
第四種,根據(jù)是否等待響應(yīng)結(jié)果,,可以把文件I/O 分為同步I/O 和 異步I/O,。在應(yīng)用程序執(zhí)行I/O 操作后,如果一直等到 整個 I/O完成后才獲得響應(yīng),,就是同步I/O,;如果不等待 I/O 完成以及完成后的響應(yīng),繼續(xù)往下執(zhí)行,,等到 I/O 完成后,,響應(yīng)會用事件通知的方式,告訴應(yīng)用程序,。比如,,在操作文件時,如果設(shè)置了 O_SYNC 或 O_DSYNC標志,,就代表同步I/O,,后者是等待文件數(shù)據(jù)寫入磁盤后才返回,而前者是在后者基礎(chǔ)上,,要求文件元數(shù)據(jù)也要寫入磁盤后才能返回,。再比如,在訪問管道或者網(wǎng)絡(luò)套接字時,,設(shè)置選項 O_ASYNC后,,就是異步 I/O內(nèi)核會通過 SIGIO 或者 SIGPOLL,,來通知進程,文件是否可讀寫,。
總之,,無論是普通文件和塊設(shè)備、還是網(wǎng)絡(luò)套接字和管道等,,都通過統(tǒng)一的VFS接口來被訪問,。
4. 文件系統(tǒng)性能觀測
加上-i 參數(shù)查看索引節(jié)點的使用情況,索引節(jié)點的容量,,(也就是 Inode個數(shù))是在格式化磁盤時設(shè)定好的,,由格式化工具自動生成。當你發(fā)現(xiàn)索引節(jié)點空間不足時,,但磁盤空間充足時,,很可能是過多的小文件導致的,一般的刪除它們或者移到其他的索引節(jié)點充足的磁盤上,,就能解決問題,。
接下來,文件系統(tǒng)的目錄項和索引節(jié)點的緩存,,如何查看呢,?
實際上,內(nèi)核使用 Slab 機制,,管理目錄項和索引節(jié)點的緩存,。/proc/meminfo 只給出了Slab整體大小,具體到每一種Slab緩存,,就要查看 /proc/slabinfo,。運行下面命令可以得到,所有目錄項和各種文件系統(tǒng)的索引節(jié)點的緩存情況:
dentry 行表示目錄項緩存,,inode_cache 行,,表示VFS 索引節(jié)點緩存,其余的則是各種文件系統(tǒng)的緩存,。這里列比較多,,可查詢man slabinfo。實際性能分析時,,更多使用 slabtop,,來找到占用內(nèi)存最多的緩存類型:
從這個結(jié)果可以看到,目錄項和索引節(jié)點占用最多的 Slab緩存,,但其實并不大,,約23MB。
思考:find / -name file-name 命令導致會不會導致緩存升高,,如果會,,導致哪類緩存升高呢,?
find / -name 命令是全盤掃描(包括內(nèi)存文件系統(tǒng)、磁盤文件系統(tǒng)等),,所以這里會導致 xfs_inode 、proc_inode_cache,、dentry,、 inode_cache這幾類緩存的升高,而且在下次執(zhí)行 find 命令時,,就會快很多,,因為它大部分會直接在緩存中查找結(jié)果。這里你可以在執(zhí)行find命令前后,,比較slabtop,、free、vmstat輸出結(jié)果,,又會有更深的理解,。
磁盤 I/O
1. 磁盤
首先,根據(jù)存儲介質(zhì)的不同,,可以分為兩類,,機械磁盤 和 固態(tài)磁盤。
機械磁盤:也稱為硬盤驅(qū)動器(Hard Disk Driver,,縮寫HDD),,機械磁盤由盤片和讀寫磁頭組成,數(shù)據(jù)存儲在盤片的環(huán)狀磁道中,,最小讀寫單位 扇區(qū),,一般大小為512B。在讀寫數(shù)據(jù)時,,需要移動磁頭,,定位到數(shù)據(jù)所在的盤片磁道中,然后才訪問數(shù)據(jù),。如果 I/O 請求剛好連續(xù),,那就不需要磁道尋址,可獲得最佳性能,,這就是順序I/O 的工作原理,。隨機 I/O,需要不停地移動磁頭,,來定位數(shù)據(jù)位置,,讀寫速度比較慢。
固態(tài)磁盤:Solid State Driver,,縮寫SSD,,由固態(tài)電子元器件組成,,最小讀寫單位 頁,一般大小4KB,、8KB等,。固態(tài)磁盤不需要磁道尋址,不管是連續(xù)I/O,,還是隨機I/O的性能,,都比機械磁盤好得多。
另外,,相同磁盤的順序I/O 都要比 隨機I/O 快得多,,原因如下:
對于機械磁盤來說,隨機 I/O需要更多的磁頭尋道和盤片旋轉(zhuǎn),,性能比順序I/O 慢,。
對于固態(tài)盤來說,雖然隨機I/O 性能比機械盤好很多,,但是它也會有“先擦除,、再寫入”的限制。隨機讀寫也有大量的垃圾回收,,所以還是會比順序I/O 慢很多,。
另外,順序I/O 可以通過預(yù)讀的方式,,來減少 I/O請求的次數(shù),,這也是其性能優(yōu)異的原因之一。
在上一節(jié)提到過,,如果每次都讀寫 512B 數(shù)據(jù),,效率會很低。文件系統(tǒng)會把連續(xù)的扇區(qū)或頁組成邏輯塊,,作為最小單元管理數(shù)據(jù),,常見的邏輯塊是 4KB,即連續(xù)的8個扇區(qū),,或者一個頁,。
其次,還可以按照接口來分類,,可以把硬盤分為 IDE,、SCSI、SAS,、SATA,、FC等。不同的接口,分配不同的設(shè)備名稱,。比如 IDE的會分配一個前綴為 hd 的設(shè)備名,,SCSI 和 SATA會分配一個 sd 前綴的設(shè)備名。如果是多塊同類型的磁盤,,會按照a,、b、c等字母順序編號,。
第三,,還可以根據(jù)使用方式,將磁盤劃分為不同架構(gòu),。最簡單的就是,作為獨立磁盤來使用,。然后再根據(jù)需要,,將磁盤劃分成多個邏輯分區(qū),再給分區(qū)編號,。比如前面多次用到的 /dev/sda,,還可以分成兩個分區(qū) /dev/sda1 和 /dev/sda2。另一個比較常用的架構(gòu)是,,將多塊磁盤組成一個邏輯磁盤,,構(gòu)成冗余獨立 的磁盤陣列,RAID,,提高數(shù)據(jù)訪問性能,,增強數(shù)據(jù)存儲的可靠性。
根據(jù)容量,、性能,、可靠性的不同,RAID可以分為多個級別,,如RAID0,、RAID1、RAID5,、RAID10等,。RAID0有最優(yōu)的讀寫性能,但不提供數(shù)據(jù)冗余的功能,,其他級別的 RAID,,在數(shù)據(jù)冗余的基礎(chǔ)上,對讀寫性能有一定的優(yōu)化,。
最后一種架構(gòu),,把磁盤組合成網(wǎng)絡(luò)存儲集群,再通過NFS,、SMB,、iSCSI等網(wǎng)絡(luò)存儲協(xié)議,,暴露給服務(wù)器使用。
其實,,在Linux下,,磁盤是作為塊設(shè)備來管理的,也就是以塊為單位來讀寫數(shù)據(jù),,且支持隨機讀寫,。每個塊設(shè)備都被賦予主、次兩個設(shè)備號,,主設(shè)備號用在驅(qū)動程序中區(qū)別設(shè)備類型,,次設(shè)備號用來給多個同類設(shè)備編號。
2. 通用塊層
為了減少不同塊設(shè)備的差異帶來的影響,,Linux通過一個統(tǒng)一的通用塊層,,來管理各種不同的塊設(shè)備。通用塊層其實是處在文件系統(tǒng)和磁盤驅(qū)動中間的一個塊設(shè)備抽象層,。有兩個功能:
第一個跟虛擬文件系統(tǒng)的功能類似,。向上,為文件系統(tǒng)和應(yīng)用程序,,提供訪問塊設(shè)備的標準接口,;向下,把各種異構(gòu)的磁盤設(shè)備抽象成統(tǒng)一的塊設(shè)備,,并提供統(tǒng)一框架來管理這些設(shè)備的驅(qū)動程序,。
第二個功能,通用塊層還給文件系統(tǒng)和應(yīng)用程序發(fā)來的I/O請求排隊,,并通過請求排隊,、合并等,提高磁盤讀寫的效率,。
對 I/O請求排序也是 I/O調(diào)度,。事實上,Linux內(nèi)核支持四種 I/O調(diào)度算法,,NONE,、NOOP、CFQ,、DeadLine,。
NONE:確切的說并不能算調(diào)度,因為它完全不使用任何調(diào)度器,,對文件系統(tǒng)和應(yīng)用程序的 I/O不作任何處理,,常用在虛擬機中(此時磁盤 I/O調(diào)度完全由物理機支持)。
NOOP:最簡單的一種調(diào)度算法,是一個先進先出的隊列,,只做一些最基本的請求合并,,常用于SSD盤。
CFQ:完全公平調(diào)度器,,是現(xiàn)在很多發(fā)行版的默認 I/O調(diào)度器,。它為每個進程維護了一個 I/O調(diào)度隊列,并按時間片來均勻分布每個進程的 I/O請求,。類似于進程的CPU調(diào)度,,CFQ調(diào)度還支持進程 I/O的優(yōu)先級調(diào)度,所以適用運行著大量進程的系統(tǒng),,像桌面環(huán)境,、多媒體應(yīng)用等。
DeadLine:分別為讀,、寫請求創(chuàng)建不同的 I/O 隊列,,可以提高機械磁盤的吞吐量,并確保達到最終期限的請求被優(yōu)先處理,。這種調(diào)度算法 多用在 I/O 壓力比較大的場合,如數(shù)據(jù)庫等,。
3. I/O棧
結(jié)合上面講的文件系統(tǒng),、磁盤和通用塊層的工作原理,我們可以整體來看 Linux存儲系統(tǒng)的 I/O原理了,。事實上,,我們可以把 Linux存儲系統(tǒng)的 I/O棧,由上至下分為三層:文件系統(tǒng)層,、通用塊層,、設(shè)備層??磮D:
根據(jù)這張全景圖,,我們可以更清楚理解,存儲系統(tǒng)的 I/O的工作原理:
文件系統(tǒng)層,,包括虛擬文件系統(tǒng)和其他各種文件系統(tǒng)的具體實現(xiàn),。首先為上層的應(yīng)用程序提供標準的文件訪問接口,對下會通過通用塊層,,來存儲和管理磁盤數(shù)據(jù),。
通用塊層,是Linux磁盤 I/O的核心,,包括設(shè)備 I/O隊列和 I/O調(diào)度器,。會對文件系統(tǒng)的 I/O請求進行排隊,再通過重新排序和請求合并,再發(fā)給下一級設(shè)備層,。
設(shè)備層,,包括存儲設(shè)備和相應(yīng)的驅(qū)動程序,負責最終物理設(shè)備的 I/O操作,。
存儲系統(tǒng)的 I/O,,通常是整個Linux系統(tǒng)中最慢的一環(huán)。所以,,Linux通過多種緩存機制來優(yōu)化 I/O 效率,。比如,為了優(yōu)化文件訪問性能,,會使用頁緩存,、索引節(jié)點緩存、目錄項緩存等多種緩存機制,,減少對下層塊設(shè)備的直接調(diào)用,。同樣,為了優(yōu)化塊設(shè)備的訪問性能,,會使用緩沖區(qū),,來緩存塊設(shè)備的數(shù)據(jù)。
4. 磁盤性能指標以及觀測
這里說一下常見的五個指標,,使用率,、飽和度、IOPS,、吞吐量以及響應(yīng)時間等,,這五個指標是衡量磁盤性能的基本指標。
使用率,,是指磁盤處理 I/O的時間百分比,。過高的使用率(如超過80%),通常意味著磁盤 I/O的性能瓶頸,。
飽和度,,磁盤處理 I/O的繁忙程度,過高的飽和度,,意味著磁盤存在嚴重的性能瓶頸,。當達到100%時,磁盤就無法接受新的 I/O請求,。
IOPS,,每秒的 I/O請求數(shù)。
吞吐量,,每秒的 I/O請求大小,。
響應(yīng)時間,,從發(fā)出請求到收到響應(yīng)的時間間隔。
注意,,使用率只考慮有沒有 I/O,,而不考慮 I/O大小,即使達到100%,,也有可能接受新的 I/O請求,。在數(shù)據(jù)庫、大量小文件等這類隨機讀寫比較多的場景中,,IOPS更能反應(yīng)系統(tǒng)整體性能,。在多媒體等順序讀寫較多的場景中,吞吐量更能反應(yīng)系統(tǒng)整體性能,。
一般來說,,我們在為應(yīng)用程序的服務(wù)器選型時,要先對磁盤 I/O的性能進行基準測試,,推薦的性能測試工具 fio,,來測試磁盤的 IOPS,吞吐量以及響應(yīng)時間等核心指標,。用性能工具得到的指標,,作為后續(xù)分析應(yīng)用程序的性能依據(jù)。一旦發(fā)生性能問題,,就可以把它們作為磁盤性能的極限值,,進而評估磁盤 I/O的使用情況。
接下來看看怎么觀測磁盤 I/O,?首推的工具 iostat,它提供每個磁盤的使用率,、IOPS,、吞吐量等各種常見的性能指標,當然這些指標來自 /proc/diskstats,。iostats 的輸出界面如下:
下圖說明了這些列的具體含義:
這些指標,,你要注意,%util 磁盤使用率,,r/s + w/s IOPS,,rkB/s + wkB/s 吞吐量, r_await + w_await 響應(yīng)時間,。另外從 iostat 并不能直接得到磁盤的飽和度,,但是可以把觀測到的,平均請求隊列長度 或者 讀寫請求完成的等待時間,,跟基準測試的結(jié)果進行對比,,綜合來評估,。
我們再來看看,每個進程的 I/O情況,。iostat只能看到磁盤整體的 I/O性能數(shù)據(jù),,并不能知道具體哪些進程 在進行磁盤讀寫,推薦兩個工具:pidstat 和 iotop,。具體使用這里略過,。
更多信息可以來這里獲取==>>電子技術(shù)應(yīng)用-AET<<
電子技術(shù)應(yīng)用專欄作家 一口linux
原文鏈接:https://mp.weixin.qq.com/s/pOifG5m1VkSUmKOFzdi-5Q