I/O 統計欄位¶
核心透過 /proc/diskstats 和 /sys/block/<device>/stat 公開磁碟統計資訊。這些統計資訊通常透過 sar 和 iostat 等工具訪問。
以下是使用具有兩個分割槽的磁碟的示例
/proc/diskstats:
259 0 nvme0n1 255999 814 12369153 47919 996852 81 36123024 425995 0 301795 580470 0 0 0 0 60602 106555
259 1 nvme0n1p1 492 813 17572 96 848 81 108288 210 0 76 307 0 0 0 0 0 0
259 2 nvme0n1p2 255401 1 12343477 47799 996004 0 36014736 425784 0 344336 473584 0 0 0 0 0 0
/sys/block/nvme0n1/stat:
255999 814 12369153 47919 996858 81 36123056 426009 0 301809 580491 0 0 0 0 60605 106562
/sys/block/nvme0n1/nvme0n1p1/stat:
492 813 17572 96 848 81 108288 210 0 76 307 0 0 0 0 0 0
這兩個檔案包含相同的 17 個統計資訊。/sys/block/<device>/stat 包含 <device> 的欄位。在 /proc/diskstats 中,這些欄位以主裝置號和次裝置號以及裝置名稱為字首。在上面的示例中,nvme0n1 的第一個統計值在兩個檔案中都是 255999。
sysfs stat 檔案對於監控少量已知的磁碟非常有效。 如果您正在跟蹤大量裝置,則 /proc/diskstats 通常是更好的選擇,因為它避免了為每個快照開啟和關閉多個檔案的開銷。
除了欄位 9 之外,所有欄位都是累積的、單調遞增的計數器,欄位 9 在 I/O 完成時重置為零。 其餘欄位在啟動時、裝置重新連線或重新初始化時,或者當底層計數器溢位時重置。 讀取這些計數器的應用程式在比較統計快照時應檢測並處理重置。
每組統計資訊僅適用於指示的裝置; 如果您想要系統範圍的統計資訊,您必須找到所有裝置並將它們全部加起來。
- 欄位 1 -- 完成的讀取次數 (unsigned long)
這是成功完成的讀取總數。
- 欄位 2 -- 合併的讀取次數,欄位 6 -- 合併的寫入次數 (unsigned long)
彼此相鄰的讀取和寫入可以合併以提高效率。 因此,兩個 4K 讀取可能會變成一個 8K 讀取,然後再最終交給磁碟,因此它將被計為(和排隊)只有一個 I/O。 此欄位讓您知道這種情況發生的頻率。
- 欄位 3 -- 讀取的扇區數 (unsigned long)
這是成功讀取的扇區總數。
- 欄位 4 -- 讀取所花費的毫秒數 (unsigned int)
這是所有讀取花費的總毫秒數(從 blk_mq_alloc_request() 到 __blk_mq_end_request() 測量)。
- 欄位 5 -- 完成的寫入次數 (unsigned long)
這是成功完成的寫入總數。
- 欄位 6 -- 合併的寫入次數 (unsigned long)
請參閱欄位 2 的描述。
- 欄位 7 -- 寫入的扇區數 (unsigned long)
這是成功寫入的扇區總數。
- 欄位 8 -- 寫入所花費的毫秒數 (unsigned int)
這是所有寫入花費的總毫秒數(從 blk_mq_alloc_request() 到 __blk_mq_end_request() 測量)。
- 欄位 9 -- 當前正在進行的 I/O 數 (unsigned int)
唯一應該變為零的欄位。 當請求被賦予適當的 struct request_queue 時遞增,並在完成時遞減。
- 欄位 10 -- 執行 I/O 所花費的毫秒數 (unsigned int)
只要欄位 9 不為零,此欄位就會增加。
自 5.0 起,此欄位在至少一個請求已啟動或完成時計算節拍數。 如果請求執行超過 2 個節拍,則在併發請求的情況下,某些 I/O 時間可能不會被計算在內。
- 欄位 11 -- 執行 I/O 所花費的加權毫秒數 (unsigned int)
每次 I/O 開始、I/O 完成、I/O 合併或讀取這些統計資訊時,此欄位都會增加,增加的值為正在進行的 I/O 數(欄位 9)乘以自上次更新此欄位以來執行 I/O 所花費的毫秒數。 這可以輕鬆地衡量 I/O 完成時間和可能正在累積的積壓。
- 欄位 12 -- 完成的丟棄次數 (unsigned long)
這是成功完成的丟棄總數。
- 欄位 13 -- 合併的丟棄次數 (unsigned long)
請參閱欄位 2 的描述
- 欄位 14 -- 丟棄的扇區數 (unsigned long)
這是成功丟棄的扇區總數。
- 欄位 15 -- 丟棄所花費的毫秒數 (unsigned int)
這是所有丟棄花費的總毫秒數(從 blk_mq_alloc_request() 到 __blk_mq_end_request() 測量)。
- 欄位 16 -- 完成的重新整理請求數
這是成功完成的重新整理請求總數。
塊層結合了重新整理請求,並且一次最多執行一個。 這計算由磁碟執行的重新整理請求。 不跟蹤分割槽。
- 欄位 17 -- 重新整理所花費的毫秒數
這是所有重新整理請求花費的總毫秒數。
為避免引入效能瓶頸,在修改這些計數器時不會持有任何鎖。 這意味著當更改發生衝突時可能會引入微小的不準確性,因此(例如)將每個分割槽發出的所有讀取 I/O 加起來應該等於對磁碟進行的讀取 I/O ... 但是由於缺少鎖定,它可能只是非常接近。
在 2.6+ 中,每個 CPU 都有計數器,這使得缺少鎖定幾乎不是問題。 讀取統計資訊時,每個 CPU 的計數器會被求和(可能會溢位求和到的無符號長變數),並將結果提供給使用者。 沒有方便的使用者介面可以訪問每個 CPU 的計數器本身。
自 4.19 起,請求時間以納秒精度測量,並在顯示在此介面中之前截斷為毫秒。
磁碟與分割槽¶
在 2.4 和 2.6+ 之間的 I/O 子系統中存在重大變化。 因此,一些統計資訊消失了。 從相對於分割槽的磁碟地址到相對於主磁碟的磁碟地址的轉換髮生得更早。 現在所有合併和計時都在磁碟級別而不是像 2.4 中那樣在磁碟和分割槽級別進行。 因此,您將在 2.6+ 上看到與磁碟不同的分割槽統計資訊輸出。 在 2.6+ 機器上,分割槽只有 *四個* 欄位可用。 這反映在上面的示例中。
- 欄位 1 -- 發出的讀取次數
這是發給此分割槽的讀取總數。
- 欄位 2 -- 讀取的扇區數
這是請求從此分割槽讀取的扇區總數。
- 欄位 3 -- 發出的寫入次數
這是發給此分割槽的寫入總數。
- 欄位 4 -- 寫入的扇區數
這是請求寫入此分割槽的扇區總數。
請注意,由於地址已轉換為與磁碟相關的地址,並且未保留與分割槽相關的地址的記錄,因此後續讀取的成功或失敗不能歸因於該分割槽。 換句話說,分割槽的讀取次數在分割槽排隊之前不久被計數,而整個磁碟的讀取次數在完成時被計數。 這是一個微妙的區別,對於大多數情況來說可能沒有意義。
更重要的是,由於在分割槽合併之前計數讀取/寫入次數,而在磁碟合併之後計數,因此會引入錯誤。 由於典型的工作負載通常包含大量連續和相鄰的請求,因此發出的讀取/寫入次數可能比完成的讀取/寫入次數高出幾倍。
在 2.6.25 中,完整統計資訊集再次可用於分割槽,並且磁碟和分割槽統計資訊再次一致。 由於我們仍然不保留與分割槽相關的地址的記錄,因此操作歸因於在最終合併之後包含請求的第一個扇區的分割槽。 由於請求可以跨分割槽合併,因此這可能會導致一些(可能微不足道的)不準確。
其他注意事項¶
在 2.6+ 中,預設情況下不掛載 sysfs。 如果您的 Linux 發行版尚未新增它,這是您要新增到您的 /etc/fstab 中的行
none /sys sysfs defaults 0 0
在 2.6+ 中,所有磁碟統計資訊都已從 /proc/stat 中刪除。 在 2.4 中,它們同時出現在 /proc/partitions 和 /proc/stat 中,儘管 /proc/stat 中的格式與 /proc/partitions 中的格式非常不同(如果您的系統有 proc(5),請參閱它。)