《電子技術應用》
您所在的位置:首頁 > 可編程邏輯 > 其他 > Linux教學——Linux文件系統(tǒng)、磁盤I/O是怎么工作的

Linux教學——Linux文件系統(tǒng)、磁盤I/O是怎么工作的

2022-11-07
來源:電子技術應用專欄作家 一口Linux

  同CPU、內存一樣,文件系統(tǒng)磁盤I/O,也是Linux操作系統(tǒng)最核心的功能。

  磁盤為系統(tǒng)提供了最基本的持久化存儲。

  文件系統(tǒng)則在磁盤基礎上,提供了一個用來管理文件的樹狀結構。

  文件系統(tǒng)

  1. 索引節(jié)點和目錄項

  Linux中的一切都由統(tǒng)一的文件系統(tǒng)來管理,包括普通的文件和目錄,以及塊設備、套接字、管道等。Linux文件系統(tǒng)為每個文件都分配了兩個數據結構,索引節(jié)點(index node)和目錄項(directory entry),主要用來記錄文件的元信息和目錄結構。

  索引節(jié)點,簡稱為 inode,用來記錄文件的元數據,比如inode編號、文件大小、訪問權限、修改日期、數據的位置等。索引節(jié)點和文件一一對應,它跟文件內容一樣會被持久化到磁盤,所以,索引節(jié)點同樣占磁盤。

  目錄項,簡稱為dentry,用來記錄的文件的名字、索引節(jié)點指針以及與其他目錄項的關聯(lián)關系。多個關聯(lián)的目錄項,就構成了文件系統(tǒng)的目錄結構,它是由內核維護的一個內存數據結構,通常也被稱為目錄項緩存。

  換句話說,索引節(jié)點是每個文件的唯一標志,目錄項維護的是文件系統(tǒng)的樹狀結構。目錄項和索引節(jié)點的關系是多對一,或者可理解為一個文件多個別名。舉個例子,通過硬鏈接為文件創(chuàng)建的別名,就會對應不同目錄項,這些目錄項本質上是連接同一個文件,所以索引節(jié)點相同。

  更具體地說,文件數據是怎么存儲的,是直接保存到磁盤的?實際上磁盤讀寫的最小單位是扇區(qū),扇區(qū)只有512B大小,如果每次讀寫這么小的單位,效率一定很低。所以,文件系統(tǒng)又把連續(xù)的扇區(qū)組成邏輯塊,再以邏輯塊為最小單元去管理數據。常見的邏輯塊大小是4KB,即連續(xù)的8個扇區(qū)。下面展示一張示意圖:

  微信截圖_20221107172404.png

  這里需要注意兩點:

  第一,目錄項本身在內存中,索引節(jié)點在磁盤中。前面的 Buffer 和 Cache 原理中提到,為了協(xié)調慢速磁盤和快速CPU之間的性能差異,文件內容會緩存到頁緩存 Cache中。索引節(jié)點自然也會緩存到內存中,增加速文件訪問。

  第二,磁盤在執(zhí)行文件系統(tǒng)格式化時,會被分成三個存儲區(qū)域,超級塊、索引節(jié)點區(qū) 和 數據塊區(qū)。其中,超級塊存儲整個文件系統(tǒng)狀態(tài);索引節(jié)點區(qū)存儲索引節(jié)點;數據塊區(qū),存儲文件數據。

  2. 虛擬文件系統(tǒng)

  目錄項、索引節(jié)點、超級塊、邏輯塊構成Linux文件系統(tǒng)四大基本要素。不過,為了支持各種不同的文件系統(tǒng),Linux內核在用戶進程和文件系統(tǒng)中間,引入了一個抽象層,即虛擬文件系統(tǒng)VFS。VFS定義了一套所有文件系統(tǒng)都支持的數據結構和標準接口。這樣,用戶層和內核其他子系統(tǒng)都只需要跟 VFS 提供的統(tǒng)一接口交互就可以了,不需要關心底層各種文件系統(tǒng)的實現細節(jié)。下圖很好展示了Linux文件系統(tǒng)的架構圖,能更好的幫助理解系統(tǒng)調用、VFS、緩存、文件系統(tǒng)以及塊存儲之間的關系:

  微信截圖_20221107172704.png

  從圖中可以看到,在VFS下面Linux可以支持各種文件系統(tǒng),按照存儲位置的不同,可以分為三類:

  基于磁盤的文件系統(tǒng),也就是把數據直接存儲到計算機本地掛載的磁盤中。如 EXT4、XFS、OverlayFS等。

  基于內存的文件系統(tǒng),也就是虛擬文件系統(tǒng),不需要磁盤分配任何存儲空間,只占用內存。如 /proc 文件系統(tǒng)、/sys 文件系統(tǒng)(主要向用戶空間導出層次化的內核對象)。

  網絡文件系統(tǒng),用來訪問其他計算機數據的文件系統(tǒng),如 NFS、SMB、iSCSI等。

  這些文件系統(tǒng),要先掛載到 VFS 目錄樹中的子目錄(掛載點),然后才能訪問其中文件。比如安裝系統(tǒng)時,要先掛在一個根目錄( / ),在根目錄下,再把其他文件系統(tǒng)掛在進來。

  3. 文件系統(tǒng)I/O

  把文件掛到掛載點后,就能通過它去訪問它管理的文件了。VFS提供的訪問文件的標準接口,以系統(tǒng)調用的方式提供給應用程序使用。比如,cat命令,相繼調用 open()、read()、write()。文件讀寫方式的各種差異,也導致I/O 的分類多種多樣。常見的有,緩沖與非緩沖I/O、直接與非直接I/O、阻塞與非阻塞I/O、同步與異步I/O等。下面詳細解釋下這四種 I/O分類:

  第一種,根據是否利用標準庫緩存,可以把文件I/O 分為 緩沖I/O 和 非緩沖I/O。這里的“緩沖”,其實指的是標準庫內部實現的緩存。例如,很多程序遇到換行時才真正輸出,換行前的內容,就是被標準庫暫時緩存起來。因此,緩沖I/O 指的是利用標準庫緩存來加速文件的訪問,在標準庫內部再通過系統(tǒng)調用訪問文件;非緩沖I/O 指的是直接通過系統(tǒng)調用訪問文件,而不通過標準庫緩存。無論是緩沖還是非緩沖 I/O,最后都是通過系統(tǒng)調用訪問文件。而根據前面內容,系統(tǒng)調用后,還通過頁緩存,來減少磁盤I/O操作。

  第二種,根據是否利用操作系統(tǒng)的頁緩存,可以把文件I/O 分為直接I/O 和 非直接I/O。想要實現直接I/O,需要在系統(tǒng)調用中指定標志 O_DIRECT,如果不指定,默認是非直接I/O。不過注意,這里的直接、非直接I/O,其實最終還是和文件系統(tǒng)交互。如果實在數據庫等場景中,還會看到,跳過文件系統(tǒng)讀寫磁盤的情況,即裸I/O。

  第三種,根據應用程序是否阻塞自身運行,可以把文件I/O 分為阻塞I/O 和 非阻塞I/O。在應用程序執(zhí)行I/O 操作后,如果沒獲得響應,就阻塞當前線程,自然不能執(zhí)行其他任務,這是阻塞I/O;如果沒獲得響應,卻不阻塞當前線程,繼續(xù)執(zhí)行其他任務,隨后通過輪詢或者時間通知的形式,獲得之前調用的結果。比如,訪問管道或者網絡套接字時,設置 O_NONBLOCK 標志,表示非阻塞方式訪問,若不做任何設置,默認就是阻塞方式訪問。

  第四種,根據是否等待響應結果,可以把文件I/O 分為同步I/O 和 異步I/O。在應用程序執(zhí)行I/O 操作后,如果一直等到 整個 I/O完成后才獲得響應,就是同步I/O;如果不等待 I/O 完成以及完成后的響應,繼續(xù)往下執(zhí)行,等到 I/O 完成后,響應會用事件通知的方式,告訴應用程序。比如,在操作文件時,如果設置了 O_SYNC 或 O_DSYNC標志,就代表同步I/O,后者是等待文件數據寫入磁盤后才返回,而前者是在后者基礎上,要求文件元數據也要寫入磁盤后才能返回。再比如,在訪問管道或者網絡套接字時,設置選項 O_ASYNC后,就是異步 I/O內核會通過 SIGIO 或者 SIGPOLL,來通知進程,文件是否可讀寫。

  總之,無論是普通文件和塊設備、還是網絡套接字和管道等,都通過統(tǒng)一的VFS接口來被訪問。

  4. 文件系統(tǒng)性能觀測

 微信截圖_20221107172857.png

  加上-i 參數查看索引節(jié)點的使用情況,索引節(jié)點的容量,(也就是 Inode個數)是在格式化磁盤時設定好的,由格式化工具自動生成。當你發(fā)現索引節(jié)點空間不足時,但磁盤空間充足時,很可能是過多的小文件導致的,一般的刪除它們或者移到其他的索引節(jié)點充足的磁盤上,就能解決問題。

  接下來,文件系統(tǒng)的目錄項和索引節(jié)點的緩存,如何查看呢?

  實際上,內核使用 Slab 機制,管理目錄項和索引節(jié)點的緩存。/proc/meminfo 只給出了Slab整體大小,具體到每一種Slab緩存,就要查看 /proc/slabinfo。運行下面命令可以得到,所有目錄項和各種文件系統(tǒng)的索引節(jié)點的緩存情況:

 微信截圖_20221107173010.png

  dentry 行表示目錄項緩存,inode_cache 行,表示VFS 索引節(jié)點緩存,其余的則是各種文件系統(tǒng)的緩存。這里列比較多,可查詢man slabinfo。實際性能分析時,更多使用 slabtop,來找到占用內存最多的緩存類型:

  微信截圖_20221107173043.png

  從這個結果可以看到,目錄項和索引節(jié)點占用最多的 Slab緩存,但其實并不大,約23MB。

  思考:find / -name file-name 命令導致會不會導致緩存升高,如果會,導致哪類緩存升高呢?

  find / -name 命令是全盤掃描(包括內存文件系統(tǒng)、磁盤文件系統(tǒng)等),所以這里會導致 xfs_inode 、proc_inode_cache、dentry、 inode_cache這幾類緩存的升高,而且在下次執(zhí)行 find 命令時,就會快很多,因為它大部分會直接在緩存中查找結果。這里你可以在執(zhí)行find命令前后,比較slabtop、free、vmstat輸出結果,又會有更深的理解。

  磁盤 I/O

  1. 磁盤

  首先,根據存儲介質的不同,可以分為兩類,機械磁盤 和 固態(tài)磁盤。

  機械磁盤:也稱為硬盤驅動器(Hard Disk Driver,縮寫HDD),機械磁盤由盤片和讀寫磁頭組成,數據存儲在盤片的環(huán)狀磁道中,最小讀寫單位 扇區(qū),一般大小為512B。在讀寫數據時,需要移動磁頭,定位到數據所在的盤片磁道中,然后才訪問數據。如果 I/O 請求剛好連續(xù),那就不需要磁道尋址,可獲得最佳性能,這就是順序I/O 的工作原理。隨機 I/O,需要不停地移動磁頭,來定位數據位置,讀寫速度比較慢。

  固態(tài)磁盤:Solid State Driver,縮寫SSD,由固態(tài)電子元器件組成,最小讀寫單位 頁,一般大小4KB、8KB等。固態(tài)磁盤不需要磁道尋址,不管是連續(xù)I/O,還是隨機I/O的性能,都比機械磁盤好得多。

  另外,相同磁盤的順序I/O 都要比 隨機I/O 快得多,原因如下:

  對于機械磁盤來說,隨機 I/O需要更多的磁頭尋道和盤片旋轉,性能比順序I/O 慢。

  對于固態(tài)盤來說,雖然隨機I/O 性能比機械盤好很多,但是它也會有“先擦除、再寫入”的限制。隨機讀寫也有大量的垃圾回收,所以還是會比順序I/O 慢很多。

  另外,順序I/O 可以通過預讀的方式,來減少 I/O請求的次數,這也是其性能優(yōu)異的原因之一。

  在上一節(jié)提到過,如果每次都讀寫 512B 數據,效率會很低。文件系統(tǒng)會把連續(xù)的扇區(qū)或頁組成邏輯塊,作為最小單元管理數據,常見的邏輯塊是 4KB,即連續(xù)的8個扇區(qū),或者一個頁。

  其次,還可以按照接口來分類,可以把硬盤分為 IDE、SCSI、SAS、SATA、FC等。不同的接口,分配不同的設備名稱。比如 IDE的會分配一個前綴為 hd 的設備名,SCSI 和 SATA會分配一個 sd 前綴的設備名。如果是多塊同類型的磁盤,會按照a、b、c等字母順序編號。

  第三,還可以根據使用方式,將磁盤劃分為不同架構。最簡單的就是,作為獨立磁盤來使用。然后再根據需要,將磁盤劃分成多個邏輯分區(qū),再給分區(qū)編號。比如前面多次用到的 /dev/sda,還可以分成兩個分區(qū) /dev/sda1 和 /dev/sda2。另一個比較常用的架構是,將多塊磁盤組成一個邏輯磁盤,構成冗余獨立 的磁盤陣列,RAID,提高數據訪問性能,增強數據存儲的可靠性。

  根據容量、性能、可靠性的不同,RAID可以分為多個級別,如RAID0、RAID1、RAID5、RAID10等。RAID0有最優(yōu)的讀寫性能,但不提供數據冗余的功能,其他級別的 RAID,在數據冗余的基礎上,對讀寫性能有一定的優(yōu)化。

  最后一種架構,把磁盤組合成網絡存儲集群,再通過NFS、SMB、iSCSI等網絡存儲協(xié)議,暴露給服務器使用。

  其實,在Linux下,磁盤是作為塊設備來管理的,也就是以塊為單位來讀寫數據,且支持隨機讀寫。每個塊設備都被賦予主、次兩個設備號,主設備號用在驅動程序中區(qū)別設備類型,次設備號用來給多個同類設備編號。

  2. 通用塊層

  為了減少不同塊設備的差異帶來的影響,Linux通過一個統(tǒng)一的通用塊層,來管理各種不同的塊設備。通用塊層其實是處在文件系統(tǒng)和磁盤驅動中間的一個塊設備抽象層。有兩個功能:

  第一個跟虛擬文件系統(tǒng)的功能類似。向上,為文件系統(tǒng)和應用程序,提供訪問塊設備的標準接口;向下,把各種異構的磁盤設備抽象成統(tǒng)一的塊設備,并提供統(tǒng)一框架來管理這些設備的驅動程序。

  第二個功能,通用塊層還給文件系統(tǒng)和應用程序發(fā)來的I/O請求排隊,并通過請求排隊、合并等,提高磁盤讀寫的效率。

  對 I/O請求排序也是 I/O調度。事實上,Linux內核支持四種 I/O調度算法,NONE、NOOP、CFQ、DeadLine。

  NONE:確切的說并不能算調度,因為它完全不使用任何調度器,對文件系統(tǒng)和應用程序的 I/O不作任何處理,常用在虛擬機中(此時磁盤 I/O調度完全由物理機支持)。

  NOOP:最簡單的一種調度算法,是一個先進先出的隊列,只做一些最基本的請求合并,常用于SSD盤。

  CFQ:完全公平調度器,是現在很多發(fā)行版的默認 I/O調度器。它為每個進程維護了一個 I/O調度隊列,并按時間片來均勻分布每個進程的 I/O請求。類似于進程的CPU調度,CFQ調度還支持進程 I/O的優(yōu)先級調度,所以適用運行著大量進程的系統(tǒng),像桌面環(huán)境、多媒體應用等。

  DeadLine:分別為讀、寫請求創(chuàng)建不同的 I/O 隊列,可以提高機械磁盤的吞吐量,并確保達到最終期限的請求被優(yōu)先處理。這種調度算法 多用在 I/O 壓力比較大的場合,如數據庫等。

  3. I/O棧

  結合上面講的文件系統(tǒng)、磁盤和通用塊層的工作原理,我們可以整體來看 Linux存儲系統(tǒng)的 I/O原理了。事實上,我們可以把 Linux存儲系統(tǒng)的 I/O棧,由上至下分為三層:文件系統(tǒng)層、通用塊層、設備層??磮D:

  微信截圖_20221107173218.png

  根據這張全景圖,我們可以更清楚理解,存儲系統(tǒng)的 I/O的工作原理:

  文件系統(tǒng)層,包括虛擬文件系統(tǒng)和其他各種文件系統(tǒng)的具體實現。首先為上層的應用程序提供標準的文件訪問接口,對下會通過通用塊層,來存儲和管理磁盤數據。

  通用塊層,是Linux磁盤 I/O的核心,包括設備 I/O隊列和 I/O調度器。會對文件系統(tǒng)的 I/O請求進行排隊,再通過重新排序和請求合并,再發(fā)給下一級設備層。

  設備層,包括存儲設備和相應的驅動程序,負責最終物理設備的 I/O操作。

  存儲系統(tǒng)的 I/O,通常是整個Linux系統(tǒng)中最慢的一環(huán)。所以,Linux通過多種緩存機制來優(yōu)化 I/O 效率。比如,為了優(yōu)化文件訪問性能,會使用頁緩存、索引節(jié)點緩存、目錄項緩存等多種緩存機制,減少對下層塊設備的直接調用。同樣,為了優(yōu)化塊設備的訪問性能,會使用緩沖區(qū),來緩存塊設備的數據。

  4. 磁盤性能指標以及觀測

  這里說一下常見的五個指標,使用率、飽和度、IOPS、吞吐量以及響應時間等,這五個指標是衡量磁盤性能的基本指標。

  使用率,是指磁盤處理 I/O的時間百分比。過高的使用率(如超過80%),通常意味著磁盤 I/O的性能瓶頸。

  飽和度,磁盤處理 I/O的繁忙程度,過高的飽和度,意味著磁盤存在嚴重的性能瓶頸。當達到100%時,磁盤就無法接受新的 I/O請求。

  IOPS,每秒的 I/O請求數。

  吞吐量,每秒的 I/O請求大小。

  響應時間,從發(fā)出請求到收到響應的時間間隔。

  注意,使用率只考慮有沒有 I/O,而不考慮 I/O大小,即使達到100%,也有可能接受新的 I/O請求。在數據庫、大量小文件等這類隨機讀寫比較多的場景中,IOPS更能反應系統(tǒng)整體性能。在多媒體等順序讀寫較多的場景中,吞吐量更能反應系統(tǒng)整體性能。

  一般來說,我們在為應用程序的服務器選型時,要先對磁盤 I/O的性能進行基準測試,推薦的性能測試工具 fio,來測試磁盤的 IOPS,吞吐量以及響應時間等核心指標。用性能工具得到的指標,作為后續(xù)分析應用程序的性能依據。一旦發(fā)生性能問題,就可以把它們作為磁盤性能的極限值,進而評估磁盤 I/O的使用情況。

  接下來看看怎么觀測磁盤 I/O?首推的工具 iostat,它提供每個磁盤的使用率、IOPS、吞吐量等各種常見的性能指標,當然這些指標來自 /proc/diskstats。iostats 的輸出界面如下:

微信截圖_20221107173333.png

  下圖說明了這些列的具體含義:

  微信截圖_20221107173349.png

  這些指標,你要注意,%util 磁盤使用率,r/s + w/s IOPS,rkB/s + wkB/s 吞吐量, r_await + w_await 響應時間。另外從 iostat 并不能直接得到磁盤的飽和度,但是可以把觀測到的,平均請求隊列長度 或者 讀寫請求完成的等待時間,跟基準測試的結果進行對比,綜合來評估。

  我們再來看看,每個進程的 I/O情況。iostat只能看到磁盤整體的 I/O性能數據,并不能知道具體哪些進程 在進行磁盤讀寫,推薦兩個工具:pidstat 和 iotop。具體使用這里略過。

  更多信息可以來這里獲取==>>電子技術應用-AET<<

微信圖片_20210517164139.jpg

微信圖片_20220701092006.jpg

電子技術應用專欄作家  一口linux
原文鏈接:https://mp.weixin.qq.com/s/pOifG5m1VkSUmKOFzdi-5Q

本站內容除特別聲明的原創(chuàng)文章之外,轉載內容只為傳遞更多信息,并不代表本網站贊同其觀點。轉載的所有的文章、圖片、音/視頻文件等資料的版權歸版權所有權人所有。本站采用的非本站原創(chuàng)文章及圖片等內容無法一一聯(lián)系確認版權者。如涉及作品內容、版權和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當措施,避免給雙方造成不必要的經濟損失。聯(lián)系電話:010-82306118;郵箱:aet@chinaaet.com。