Linux 性能優化 - 磁盤 I-O 優化
- 文件系統
1.1. 文件系統工作原理
文件系統是在磁盤的基礎上,提供了一個用來管理文件的樹狀結構。
1.1.1. 索引節點和目錄項
在 Linux 中一切皆文件 , 文件系統, 本身是對存儲設備上的文件,進行組織管理的機制
爲了方便管理,Linux 文件系統爲每個文件都分配兩個數據結構, 索引節點(index node) 和 目錄項(directory entry) 。它們主要用來記錄文件的 元信息 和 目錄結構 。
-
索引節點,簡稱爲 inode,用來記錄文件的元數據,比如 inode 編號、文件大小、訪問權限、修改日期、數據的位置等。索引節點和文件一一對應,它跟文件內容一樣,都會被持久化存儲到磁盤中。所以記住,索引節點同樣佔用磁盤空間。
-
目錄項,簡稱爲 dentry,用來記錄文件的名字、索引節點指針以及與其他目錄項的關聯關係。多個關聯的目錄項,就構成了文件系統的目錄結構。不過,不同於索引節點,目錄項是由內核維護的一個內存數據結構,所以通常也被叫做目錄項緩存。
文件數據到底是怎麼存儲的呢?
磁盤讀寫的最小單位是扇區,然而扇區只有 512B 大小,如果每次都讀寫這麼小的單位,效率一定很低。所以,文件系統又把連續的扇區組成了邏輯塊,然後每次都以邏輯塊爲最小單元,來管理數據。常見的邏輯塊大小爲 4KB,也就是由連續的 8 個扇區組成。
注意:
-
目錄項本身就是一個內存緩存,而索引節點則是存儲在磁盤中的數據 ,Buwer 和 Cache 緩存可以協調慢速磁盤與快速 CPU 的性能差異,文件內容會緩存到頁緩存 Cache 中 , 這些索引節點自然也會緩存到內存中,加速文件的訪問。
-
磁盤在執行文件系統格式化時,會被分成三個存儲區域, 超級塊 、 索引節點區 和 數據塊區 。
-
超級塊,存儲整個文件系統的狀態。
-
索引節點區,用來存儲索引節點。
-
數據塊區,則用來存儲文件數據。
1.1.2. 虛擬文件系統
什麼是虛擬文件系統 VFS?
爲了支持各種不同的文件系統,Linux 內核在用戶進程和文件系統的中間,又引入了一個抽象層,也就是虛擬文件系統 VFS(Virtual File System)。VFS 定義了一組所有文件系統都支持的數據結構和標準接口。這樣,用戶進程和內核中的其他子系統,只需要跟 VFS 提供的統一接口進行交互就可以了,而不需要再關心底層各種文件系統的實現細節。
爲了更好地理解系統調用、VFS、緩存、文件系統以及塊存儲之間的關係 , 可以參考 Linux 文件系統的架構圖
通過這張圖可以看到,在 VFS 的下方,Linux 支持各種各樣的文件系統,如 Ext4、XFS、NFS 等等。按照存儲位置的不同,這些文件系統可以分爲三類。
-
第一類是基於磁盤的文件系統,也就是把數據直接存儲在計算機本地掛載的磁盤中。常見的 Ext4、XFS、OverlayFS 等,都是這類文件系統。
-
第二類是基於內存的文件系統,也就是我們常說的虛擬文件系統。這類文件系統,不需要任何磁盤分配存儲空間,但會佔用內存。我們經常用到的 /proc 就是一種最常見的虛擬文件系統。
-
第三類是網絡文件系統,也就是用來訪問其他計算機數據的文件系統,比如 NFS、SMB、iSCSI 等。
這些文件系統,要先掛載到 VFS 目錄樹中的某個子目錄(稱爲掛載點),然後才能訪問其中的文件。拿第一類,也就是基於磁盤的文件系統爲例,在安裝系統時,要先掛載一個根目錄(/),在根目錄下再把其他文件系統(比如其他的磁盤分區、/proc 文件系統、/sys 文件系統、NFS 等)掛載進來。
- 磁盤 I/O 工作原理
2.1. 磁盤類型
2.1.1. 根據介質不同分類
磁盤是可以持久化存儲的設備,根據存儲介質的不同,常見磁盤可以分爲兩類:機械磁盤和固態磁盤。
第一類,機械磁盤(Hard Disk Driver),也稱爲硬盤驅動器,通常縮寫爲 HDD。機械磁盤主要由盤片和讀寫磁頭組成,數據就存儲在盤片的環狀磁道中。在讀寫數據前,需要移動讀寫磁頭,定位到數據所在的磁道,然後才能訪問數據。
如果 I/O 請求剛好連續,那就不需要磁道尋址,自然可以獲得最佳性能。這其實就是我們熟悉的,連續 I/O 的工作原理。與之相對應的,當然就是隨機 I/O,它需要不停地移動磁頭,來定位數據位置,所以讀寫速度就會比較慢。
第二類,固態磁盤(Solid State Disk),通常縮寫爲 SSD,由固態電子元器件組成。固態磁盤不需要磁道尋址,所以,不管是連續 I/O,還是隨機 I/O 的性能,都比機械磁盤要好得多。
其實,無論機械磁盤,還是固態磁盤,相同磁盤的隨機 I/O 都要比連續 I/O 慢很多,原因也很明顯。
-
對機械磁盤來說,我們剛剛提到過的,由於隨機 I/O 需要更多的磁頭尋道和盤片旋轉,它的性能自然要比連續 I/O 慢。
-
而對固態磁盤來說,雖然它的隨機性能比機械硬盤好很多,但同樣存在 “先擦除再寫入” 的限制。隨機讀寫會導致大量的垃圾回收,所以相對應的,隨機 I/O 的性能比起連續 I/O 來,也還是差了很多。
-
此外,連續 I/O 還可以通過預讀的方式,來減少 I/O 請求的次數,這也是其性能優異的一個原因。很多性能優化的方案,也都會從這個角度出發,來優化 I/O 性能。
機械磁盤和固態磁盤還分別有一個最小的讀寫單位。
-
機械磁盤的最小讀寫單位是扇區,一般大小爲 512 字節。
-
而固態磁盤的最小讀寫單位是頁,通常大小是 4KB、8KB 等。
2.1.2. 磁盤按照接口分類
按照接口來分類,比如可以把硬盤分爲 IDE(Integrated Drive Electronics) 、 SCSI(Small Computer System Interface) 、 SAS(Serial Attached SCSI) 、 SATA(Serial ATA) 、 FC(Fibre Channel)等。
不同的接口,往往分配不同的設備名稱。比如, IDE 設備會分配一個 hd 前綴的設備名,SCSI 和 SATA 設備會分配一個 sd 前綴的設備名。如果是多塊同類型的磁盤,就會按照 a、b、c 等的字母順序來編號。
2.1.3. 按照使用方式分類
把多塊磁盤組合成一個邏輯磁盤,構成冗餘獨立磁盤陣列,也就是 RAID(Redundant Array of Independent Disks),從而可以提高數據訪問的性能,並且增強數據存儲的可靠性。
根據容量、性能和可靠性需求的不同,RAID 一般可以劃分爲多個級別,如 RAID0、RAID1、RAID5、RAID10 等。RAID0 有最優的讀寫性能,但不提供數據冗餘的功能。
而其他級別的 RAID,在提供數據冗餘的基礎上,對讀寫性能也有一定程度的優化。
最後一種架構,是把這些磁盤組合成一個網絡存儲集羣,再通過 NFS、SMB、iSCSI 等網絡存儲協議,暴露給服務器使用。
在 Linux 中,磁盤實際上是作爲一個塊設備來管理的,也就是以塊爲單位讀寫數據,並且支持隨機讀寫。每個塊設備都會被賦予兩個設備號,分別是主、次設備號。主設備號用在驅動程序中,用來區分設備類型;而次設備號則是用來給多個同類設備編號。
2.2.IO 棧
Linux 的 IO 路徑可能是 Linux 系統中比較複雜的模塊,它直接決定了系統的性能。
根據這張 I/O 棧的全景圖,我們可以更清楚地理解,存儲系統 I/O 的工作原理。
應用程序:
通過相關係統調用 (如 open/read/write) 發起 IO 請求,屬於 IO 請求的源頭;
文件系統:
應用程序的請求直接到達文件系統層。文件系統又分爲 VFS 和具體文件系統(ext3、ext4 等),VFS 對應用層提供統一的訪問接口,而 ext3 等文件系統則實現了這些接口。另外,提高 IO 性能,在該層還實現了諸如 page cache 等功能。同時,用戶也可以選擇繞過 page cache,而是直接使用 direct 模式進行 IO(如數據庫)。
塊設備層:
文件系統將 IO 請求打包提交給塊設備層,該層會對這些 IO 請求作合併、排序、調度等,然後以新的格式發往更底層。在該層次上實現了多種電梯調度算法,如 cfq、deadline 等。
SCSI 層:
塊設備層將請求發往 SCSI 層,SCSI 就開始真實處理這些 IO 請求,但是 SCSI 層又對其內部按照功能劃分了不同層次: * SCSI 高層:高層驅動負責管理 disk,接收塊設備層發出的 IO 請求,打包成 SCSI 層可識別的命令格式,繼續往下發;SCSI 中層:中層負責通用功能,如錯誤處理,超時重試等; SCSI 低層:底層負責識別物理設備,將其抽象提供給高層,同時接收高層派發的 scsi 命令,交給物理設備處理。
- 性能指標
3.1. 磁盤 I/O 性能指標
我們需要了解磁盤 I/O 性能監控的指標,以及每個指標的所揭示的磁盤某方面的性能。磁盤 I/O 性能監控的指標主要包括:
1). 每秒 I/O 數( IOPS )
一次磁盤的連續讀或者連續寫稱爲一次磁盤 I/O, 磁盤的 IOPS 就是每秒磁盤連續讀次數和連續寫次數之和。
2). 吞吐量( Throughput)
指硬盤傳輸數據流的速度,傳輸數據爲讀出數據和寫入數據的和。
3). 平均 I/O 數據尺寸
平均 I/O 數據尺寸爲吞吐量除以 I/O 數目,該指標對揭示磁盤使用模式有重要意義。
4). 磁盤活動時間百分比( Utilization) %util
磁盤處於活動時間的百分比,即磁盤利用率,磁盤在數據傳輸和處理命令處於活動狀態。
5). 服務時間( ServiceTime) svctm
指磁盤讀或寫操作執行的時間,包括尋道,數據傳輸等時間。
6).I/O 等待隊列長度( Queue Length)
指待處理的 I/O 請求的數目,如果 I/O 請求壓力持續超出磁盤處理能力,該值將增加。
7). 等待時間( Wait Time)
指磁盤讀或寫操作等待執行的時間,即在隊列中排隊的時間。
3.2. 磁盤 I/O 觀測
iostat 是最常用的磁盤 I/O 性能觀測工具,它提供了每個磁盤的 使用率 、 IOPS 、 吞吐量 等各種常見的性能指標,當然,這些指標實際上來自 /proc/diskstats。
1.命令格式:iostat [參數][時間][次數]
2.常用參數:
-
-c : 僅顯示 cpu 的狀態
-
-d : 顯示磁盤使用情況,不可以和 -c 一起使用
-
-k : 默認顯示的是讀入讀出的 block 信息,以 KB 爲單位顯示
-
-m : 以 M 爲單位顯示
-
-t : 顯示終端和 CPU 的信息
-
-x : 顯示詳細信息
-
顯示所有磁盤 I/O 的指標
- 磁盤每一列的含義如下:
- 需要注意的指標
-
%util ,就是我們前面提到的磁盤 I/O 使用率;
-
r/s+ w/s ,就是 IOPS;
-
rkB/s+wkB/s ,就是吞吐量;
-
r_await+w_await ,就是響應時間。
-
iostat 並不能直接得到磁盤飽和度。可以把觀測到的,平均請求隊列長度或者讀寫請求完成的等待時間,跟基準測試的結果進行對比,綜合評估磁盤的飽和情況。
3.3. 進程 I/O 觀測
要觀察進程的 I/O 情況,還可以使用 pidstat 和 iotop 這兩個工具。
3.3.1.pidstat 觀測 I/O
pidstat 給它加上 -d 參數 (使用 - d 選項,可以查看進程 IO 的統計信息),就可以看到進程的 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 rsyslogd
從 pidstat 的輸出能看到,它可以實時查看每個進程的 I/O 情況,包括下面這些內容。
-
用戶 ID(UID)和進程 ID(PID) 。
-
每秒讀取的數據大小(kB_rd/s) ,單位是 KB。
-
每秒發出的寫請求數據大小(kB_wr/s) ,單位是 KB。
-
每秒取消的寫請求數據大小(kB_ccwr/s) ,單位是 KB。
-
塊 I/O 延遲(iodelay),包括等待同步塊 I/O 和換入塊 I/O 結束的時間,單位是時鐘週期。
3.3.2.iotop 觀測 I/O
iotop 是一個類似於 top 的工具,可以按照 I/O 大小對進程排序,然後找到 I/O 較大的那些進程。如果沒有該命令,請通過 yum install iotop 進行安裝
從這個輸出可以看到,前兩行分別表示,進程的磁盤讀寫大小總數和磁盤真實的讀寫大小總數。因爲緩存、緩衝區、I/O 合併等因素的影響,它們可能並不相等。
剩下的部分,則是從各個角度來分別表示進程的 I/O 情況,包括線程 ID、I/O 優先級、每秒讀磁盤的大小、每秒寫磁盤的大小、換入和等待 I/O 的時鐘百分比等。
- 性能工具
第一個維度,從文件系統和磁盤 I/O 的性能指標出發。換句話說,當你想查看某個性能指標時,要清楚知道,哪些工具可以做到
第二個維度,從工具出發。也就是當你已經安裝了某個工具後,要知道這個工具能提供哪些指標。
根據工具查詢指標
- 磁盤 I/O 優化策略
5.1. 應用程序優化策略
-
可以用追加寫代替隨機寫,減少尋址開銷,加快 I/O 寫的速度。
-
可以藉助緩存 I/O ,充分利用系統緩存,降低實際 I/O 的次數。
-
可以在應用程序內部構建自己的緩存,或者用 Redis 這類外部緩存系統。
-
需要頻繁讀寫同一塊磁盤空間時,可以用 mmap 代替 read/write,減少內存的拷貝次數。
-
在需要同步寫的場景中,儘量將寫請求合併,而不是讓每個請求都同步寫入磁盤。
-
在多個應用程序共享相同磁盤時,爲了保證 I/O 不被某個應用完全佔用,推薦你使用 cgroups 的 I/O 子系統,來限制進程 / 進程組的 IOPS 以及吞吐量。
5.2. 文件系統優化策略
-
可以根據實際負載場景的不同,選擇最適合的文件系統。比如 Ubuntu 默認使用 ext4 文件系統,而 CentOS 7 默認使用 xfs 文件系統。
-
在選好文件系統後,還可以進一步優化文件系統的配置選項 。
-
可以優化文件系統的緩存 。
5.3. 磁盤優化策略
磁盤也是整個 I/O 棧的最底層。從磁盤角度出發,自然也有很多有效的性能優化方法
-
最簡單有效的優化方法,就是換用性能更好的磁盤,比如用 SSD 替代 HDD。
-
我們可以使用 RAID ,把多塊磁盤組合成一個邏輯磁盤,構成冗餘獨立磁盤陣列。這樣既可以提高數據的可靠性,又可以提升數據的訪問性能。
-
針對磁盤和應用程序 I/O 模式的特徵,我們可以選擇最適合的 I/O 調度算法。比方說,SSD 和虛擬機中的磁盤,通常用的是 noop 調度算法。而數據庫應用,我更推薦使用 deadline 算法。
-
我們可以對應用程序的數據,進行磁盤級別的隔離 。
-
在順序讀比較多的場景中,我們可以增大磁盤的預讀數據 。
-
我們可以優化內核塊設備 I/O 的選項。比如,可以調整磁盤隊列的長度, 以提升磁盤的吞吐量 。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/2b1a0TD6g-g5ikYFUHeO_g