Linux 性能優化實戰 磁盤


磁盤

磁盤為系統提供了最基本的持久化存儲。

文件系統

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

組織方式不同,就會形成不同的文件系統。

為了方便管理,Linux 文件系統為每個文件都分配兩個數據結構,索引節點(index node)和目錄項(directory entry)。它們主要用來記錄文件的元信息和目錄結構。

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

  • 目錄項,簡稱為 dentry,用來記錄文件的名字、索引節點指針以及與其他目錄項的關聯關系。多個關聯的目錄項,就構成了文件系統的目錄結構。不過,不同於索引節點,目錄項是由內核維護的一個內存數據結構,所以通常也被叫做目錄項緩存。

引節點是每個文件的唯一標志,而目錄項維護的正是文件系統的樹狀結構。目錄項和索引節點的關系是多對一,你可以簡單理解為,一個文件可以有多個別名。

舉個例子,通過硬鏈接為文件創建的別名,就會對應不同的目錄項,不過這些目錄項本質上還是鏈接同一個文件,所以,它們的索引節點相同

磁盤讀寫的最小單位是扇區,然而扇區只有 512B 大小,如果每次都讀寫這么小的單位,效率一定很低。所以,文件系統又把連續的扇區組成了邏輯塊,然后每次都以邏輯塊為最小單元,來管理數據。常見的邏輯塊大小為 4KB,也就是由連續的 8 個扇區組成。

img

不過,這里有兩點需要你注意。

第一,目錄項dentry本身就是一個內存緩存,而超級塊、索引節點和邏輯塊,都是存儲在磁盤中的持久化數據為了協調慢速磁盤與快速 CPU 的性能差異,文件內容會緩存到page Cache 中。索引節點inode也會緩存到內存中,加速文件的訪問。

第二,磁盤在執行文件系統格式化時,會被分成三個存儲區域,超級塊、索引節點區和數據塊區。

  • 超級塊,存儲整個文件系統的狀態。

  • 索引節點區,用來存儲索引節點。

    • 索引節點的容量,(也就是 Inode 個數)是在格式化磁盤時設定好的,一般由格式化工具自動生成。當你發現索引節點空間不足,但磁盤空間充足時,很可能就是過多小文件導致的。

  • 數據塊區,則用來存儲文件數據。

虛擬文件系統 VFS(Virtual File System)

Linux 文件系統的四大基本要素

  • 目錄項,記錄了文件的名字,以及文件與其他目錄項之間的目錄關系。

  • 索引節點,記錄了文件的元數據。inode編號,

  • 邏輯塊,是由連續磁盤扇區構成的最小讀寫單元,用來存儲文件數據。

  • 超級塊,用來記錄文件系統整體的狀態,如索引節點和邏輯塊的使用情況等。

為了支持各種不同的文件系統,Linux 內核在用戶進程和文件系統的中間又引入了一個抽象層,也就是虛擬文件系統 VFS(Virtual File System)。

VFS 定義了一組所有文件系統都支持的數據結構和標准接口

img

三類文件系統

按照存儲位置的不同,這些文件系統可以分為三類。

第一類是基於磁盤的文件系統,也就是把數據直接存儲在計算機本地掛載的磁盤中。常見的 Ext4、XFS、OverlayFS 等,都是這類文件系統。

第二類是基於內存的文件系統,也就是我們常說的虛擬文件系統。這類文件系統,不需要任何磁盤分配存儲空間,但會占用內存。我們經常用到的 /proc 文件系統,其實就是一種最常見的虛擬文件系統。此外,/sys 文件系統也屬於這一類,主要向用戶空間導出層次化的內核對象。

第三類是網絡文件系統,也就是用來訪問其他計算機數據的文件系統,比如 NFS、SMB、iSCSI 等。

I/O

把文件系統掛載到掛載點后,你就能通過掛載點,再去訪問它管理的文件了。VFS 提供了一組標准的文件訪問接口。這些接口以系統調用的方式,提供給應用程序使用。就拿 cat 命令來說,它首先調用 open() ,打開一個文件;然后調用 read() ,讀取文件的內容;最后再調用 write() ,把文件內容輸出到控制台的標准輸出中:

int open(const char *pathname, int flags, mode_t mode); 
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

緩沖與非緩沖 I/O、直接與非直接 I/O、阻塞與非阻塞 I/O、同步與異步 I/O

緩沖與非緩沖 I/O

根據是否利用標准庫緩存,可以把文件 I/O 分為緩沖 I/O 與非緩沖 I/O。

  • 緩沖 I/O,是指利用標准庫緩存來加速文件的訪問,而標准庫內部再通過系統調度訪問文件。

  • 非緩沖 I/O,是指直接通過系統調用來訪問文件,不再經過標准庫緩存。

    注意,這里所說的“緩沖”,是指標准庫內部實現的緩存。比方說,你可能見到過,很多程序遇到換行時才真正輸出,而換行前的內容,其實就是被標准庫暫時緩存了起來。無論緩沖 I/O 還是非緩沖 I/O,它們最終還是要經過系統調用來訪問文件。而根據上一節內容,我們知道,系統調用后,還會通過頁緩存,來減少磁盤的 I/O 操作。

直接與非直接 I/O

根據是否利用操作系統的頁緩存,可以把文件 I/O 分為直接 I/O 與非直接 I/O。

  • 直接 I/O,是指跳過操作系統的頁緩存,直接跟文件系統交互來訪問文件。

  • 非直接 I/O 正好相反,文件讀寫時,先要經過系統的頁緩存,然后再由內核或額外的系統調用,真正寫入磁盤。想要實現直接 I/O,需要你在系統調用中,指定 O_DIRECT 標志。如果沒有設置過,默認的是非直接 I/O。

    不過要注意,直接 I/O、非直接 I/O,本質上還是和文件系統交互。如果是在數據庫等場景中,你還會看到,跳過文件系統讀寫磁盤的情況,也就是我們通常所說的裸 I/O。


阻塞與非阻塞 I/O

根據應用程序是否阻塞自身運行,可以把文件 I/O 分為阻塞 I/O 和非阻塞 I/O:

  • 所謂阻塞 I/O,是指應用程序執行 I/O 操作后,如果沒有獲得響應,就會阻塞當前線程,自然就不能執行其他任務。

  • 所謂非阻塞 I/O,是指應用程序執行 I/O 操作后,不會阻塞當前的線程,可以繼續執行其他的任務,隨后再通過輪詢或者事件通知的形式,獲取調用的結果。

    比方說,訪問管道或者網絡套接字時,設置 O_NONBLOCK 標志,就表示用非阻塞方式訪問;而如果不做任何設置,默認的就是阻塞訪問。

同步和異步 I/O

根據是否等待響應結果,可以把文件 I/O 分為同步和異步 I/O:

  • 所謂同步 I/O,是指應用程序執行 I/O 操作后,要一直等到整個 I/O 完成后,才能獲得 I/O 響應。

  • 所謂異步 I/O,是指應用程序執行 I/O 操作后,不用等待完成和完成后的響應,而是繼續執行就可以。等到這次 I/O 完成后,響應會用事件通知的方式,告訴應用程序。

舉個例子,在操作文件時,如果你設置了 O_SYNC 或者 O_DSYNC 標志,就代表同步 I/O。

如果設置了 O_DSYNC,就要等文件數據寫入磁盤后,才能返回;而 O_SYNC,則是在 O_DSYNC 基礎上,要求文件元數據也要寫入磁盤后,才能返回。

再比如,在訪問管道或者網絡套接字時,設置了 O_ASYNC 選項后,相應的 I/O 就是異步 I/O。這樣,內核會再通過 SIGIO 或者 SIGPOLL,來通知進程文件是否可讀寫。

你可能發現了,這里的好多概念也經常出現在網絡編程中。比如非阻塞 I/O,通常會跟 select/poll 配合,用在網絡套接字的 I/O 中。

阻塞 / 非阻塞和同步 / 異步,其實就是兩個不同角度的 I/O 划分方式。它們描述的對象也不同,阻塞 / 非阻塞針對的是 I/O 調用者(即應用程序),而同步 / 異步針對的是 I/O 執行者(即系統)。

通用塊層

在 Linux 中,磁盤實際上是作為一個塊設備來管理的,也就是以塊為單位讀寫數據,並且支持隨機讀寫。每個塊設備都會被賦予兩個設備號,分別是主、次設備號。主設備號用在驅動程序中,用來區分設備類型;而次設備號則是用來給多個同類設備編號。

通用塊層: 處在文件系統和磁盤驅動中間的一個塊設備抽象層。

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

  • 第二個功能,通用塊層還會給文件系統和應用程序發來的 I/O 請求排隊,並通過重新排序、請求合並等方式,提高磁盤讀寫的效率。

Linux 內核支持四種 I/O 調度算法,分別是 NONE、NOOP、CFQ 以及 DeadLine。

  • NONE ,更確切來說,並不能算 I/O 調度算法。因為它完全不使用任何 I/O 調度器,對文件系統和應用程序的 I/O 其實不做任何處理,常用在虛擬機中(此時磁盤 I/O 調度完全由物理機負責)。

  • NOOP ,是最簡單的一種 I/O 調度算法。它實際上是一個先入先出的隊列,只做一些最基本的請求合並,常用於 SSD 磁盤。

  • CFQ(Completely Fair Scheduler),也被稱為完全公平調度器,是現在很多發行版的默認 I/O 調度器,它為每個進程維護了一個 I/O 調度隊列,並按照時間片來均勻分布每個進程的 I/O 請求。類似於進程 CPU 調度,CFQ 還支持進程 I/O 的優先級調度,所以它適用於運行大量進程的系統,像是桌面環境、多媒體應用等。

  • DeadLine 調度算法,分別為讀、寫請求創建了不同的 I/O 隊列,可以提高機械磁盤的吞吐量,並確保達到最終期限(deadline)的請求被優先處理。DeadLine 調度算法,多用在 I/O 壓力比較重的場景,比如數據庫等。

I/O棧

由上到下分為三個層次,分別是文件系統層、通用塊層和設備層。這三個 I/O 層的關系如下圖所示,這其實也是 Linux 存儲系統的 I/O 棧全景圖。

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

  • 通用塊層,包括塊設備 I/O 隊列和 I/O 調度器。它會對文件系統的 I/O 請求進行排隊,再通過重新排序和請求合並,然后才要發送給下一級的設備層。

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

img

(圖片來自 Linux Storage Stack Diagram )

磁盤性能指標

五個常見指標,使用率、飽和度、IOPS、吞吐量以及響應時間

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

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

  • IOPS(Input/Output Per Second),是指每秒的 I/O 請求數。

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

  • 響應時間,是指 I/O 請求從發出到收到響應的間隔時間。

磁盤 I/O 觀測

iostat 是最常用的磁盤 I/O 性能觀測工具,它提供了每個磁盤的使用率、IOPS、吞吐量等各種常見的性能指標,當然,這些指標實際上來自 /proc/diskstats。

# -d -x表示顯示所有磁盤I/O的指標
$ iostat -d -x 1
Device           r/s     w/s     rkB/s     wkB/s   rrqm/s   wrqm/s %rrqm %wrqm r_await w_await aqu-sz rareq-sz wareq-sz svctm %util
loop0           0.00   0.00     0.00     0.00     0.00     0.00   0.00   0.00   0.00   0.00   0.00     0.00     0.00   0.00   0.00
loop1           0.00   0.00     0.00     0.00     0.00     0.00   0.00   0.00   0.00   0.00   0.00     0.00     0.00   0.00   0.00
sda             0.00   0.00     0.00     0.00     0.00     0.00   0.00   0.00   0.00   0.00   0.00     0.00     0.00   0.00   0.00
sdb             0.00   0.00     0.00     0.00     0.00     0.00   0.00   0.00   0.00   0.00   0.00     0.00     0.00   0.00   0.00 1234567

 

img

 

  • %util ,就是我們前面提到的磁盤 I/O 使用率;

  • r/s+ w/s ,就是 IOPS;

  • rkB/s+wkB/s ,就是吞吐量;

  • r_await+w_await ,就是響應時間

進程 I/O 觀測

pidstat 加上 -d 參數,就可以看到進程的 I/O 情況

$ pidstat -d 1 
13:39:51     UID       PID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay Command
13:39:52     102       916     0.00     4.00     0.00       0 rsyslogd123
  • 用戶 ID(UID)和進程 ID(PID) 。

  • 每秒讀取的數據大小(kB_rd/s) ,單位是 KB。

  • 每秒發出的寫請求數據大小(kB_wr/s) ,單位是 KB。

  • 每秒取消的寫請求數據大小(kB_ccwr/s) ,單位是 KB。

  • 塊 I/O 延遲(iodelay),包括等待同步塊 I/O 和換入塊 I/O 結束的時間,單位是時鍾周期。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM