91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

磁盤IO問題的定位根因與調(diào)優(yōu)解決思路

馬哥Linux運(yùn)維 ? 來源:馬哥Linux運(yùn)維 ? 2026-02-24 14:11 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

一、概述

1.1 背景介紹

監(jiān)控大屏上iowait突然飆到 80%,SSH 連上去敲個(gè)ls要等 5 秒才有響應(yīng),業(yè)務(wù)日志瘋狂報(bào)超時(shí),數(shù)據(jù)庫慢查詢告警刷屏。這種場(chǎng)景在 SRE 的日常里出現(xiàn)頻率極高,尤其是跑著 MySQL、Elasticsearch、Kafka 這類重 IO 業(yè)務(wù)的機(jī)器上。CPU 看著不高,內(nèi)存也沒爆,但系統(tǒng)就是卡得像被凍住了一樣——十有八九是磁盤 IO 出了問題。

磁盤 IO 問題的棘手之處在于,它不像 CPU 打滿那樣一眼就能看出來。IO 瓶頸可能藏在文件系統(tǒng)層、Block 層、設(shè)備驅(qū)動(dòng)層,甚至是 RAID 卡的緩存策略里。一個(gè)%util100% 到底意味著什么?await高是磁盤慢還是隊(duì)列深?svctm這個(gè)指標(biāo)還能不能信?這些問題如果搞不清楚,排查就會(huì)走彎路。

這篇文章從 Linux IO 棧的全貌講起,把 iostat、iotop、blktrace、fio、bpftrace 這套工具鏈串起來,覆蓋從"發(fā)現(xiàn) IO 問題"到"定位根因"再到"調(diào)優(yōu)解決"的完整鏈路。

1.2 技術(shù)特點(diǎn)

全棧視角:從 VFS 到塊設(shè)備驅(qū)動(dòng),逐層拆解 IO 路徑,不停留在工具表面

工具鏈完整:iostat 看全局、iotop 定進(jìn)程、blktrace 追請(qǐng)求、fio 做基準(zhǔn)、bpftrace 抓延遲

面向?qū)崙?zhàn):每個(gè)工具都給出真實(shí)場(chǎng)景下的輸出解讀,不是照搬 man page

調(diào)優(yōu)閉環(huán):不只是發(fā)現(xiàn)問題,還覆蓋 readahead、dirty ratio、調(diào)度器等內(nèi)核參數(shù)調(diào)優(yōu)

1.3 適用場(chǎng)景

場(chǎng)景一:生產(chǎn)環(huán)境突發(fā) IO 飆升,系統(tǒng)響應(yīng)變慢甚至卡死,需要快速定位是哪個(gè)進(jìn)程在瘋狂讀寫

場(chǎng)景二:數(shù)據(jù)庫服務(wù)器 IO 延遲周期性升高,需要區(qū)分是磁盤性能不足還是應(yīng)用層 IO 模式有問題

場(chǎng)景三:新機(jī)器上線前需要做磁盤性能基準(zhǔn)測(cè)試,評(píng)估 SSD/HDD 是否滿足業(yè)務(wù) IOPS 和吞吐需求

場(chǎng)景四:容器環(huán)境下多個(gè) Pod 共享磁盤,需要找出 IO 資源的爭搶源頭

1.4 環(huán)境要求

組件 版本要求 說明
操作系統(tǒng) Ubuntu 24.04 LTS / RHEL 9.x 內(nèi)核 6.8+,支持 io.latency cgroup 控制器
sysstat 12.7+ 提供 iostat、sar 等工具
iotop 0.6+ / iotop-c 1.26+ 進(jìn)程級(jí) IO 監(jiān)控,推薦 iotop-c(C 語言重寫版)
blktrace 1.3+ 塊設(shè)備層追蹤
fio 3.37+ 磁盤基準(zhǔn)測(cè)試
bpftrace 0.21+ eBPF 追蹤 IO 延遲分布
perf 6.8+ 內(nèi)核性能分析

二、Linux IO 棧全景與調(diào)度器

要排查 IO 問題,首先得搞清楚一個(gè) IO 請(qǐng)求從應(yīng)用程序發(fā)出到磁盤完成,中間經(jīng)過了哪些環(huán)節(jié)。不理解 IO 棧的層次結(jié)構(gòu),看 iostat 的輸出就只是在看數(shù)字。

2.1 IO 棧分層架構(gòu)

應(yīng)用程序 (read/write/pread/pwrite/io_uring)
  |
  v
VFS (Virtual File System) --- Page Cache
  |
  v
文件系統(tǒng) (ext4 / xfs / btrfs)
  |
  v
Block Layer (通用塊層)
  | - IO 合并 (merge)
  | - IO 調(diào)度 (mq-deadline/bfq/kyber/none)
  | - 請(qǐng)求隊(duì)列 (多隊(duì)列 blk-mq)
  v
設(shè)備驅(qū)動(dòng) (NVMe driver / SCSI / virtio-blk)
  |
  v
物理設(shè)備 (NVMe SSD / SATA SSD / HDD / 云盤)

每一層都可能成為瓶頸,排查時(shí)需要逐層排除:

VFS + Page Cache 層:大部分讀請(qǐng)求會(huì)命中 Page Cache 直接返回,根本不會(huì)到磁盤。如果free -h看到buff/cache很小,或者sar -B顯示pgpgin很高,說明緩存命中率低,大量讀請(qǐng)求穿透到了磁盤。寫請(qǐng)求默認(rèn)走 writeback 模式,先寫到 Page Cache 的臟頁里,由內(nèi)核的pdflush/flush線程異步刷盤。

文件系統(tǒng)層:ext4 的 journal 寫入、xfs 的 log 寫入都會(huì)產(chǎn)生額外的 IO。文件系統(tǒng)碎片化嚴(yán)重時(shí),順序讀會(huì)退化成隨機(jī)讀。filefrag命令可以查看文件碎片程度。

Block Layer:這是 iostat 能觀測(cè)到的層。IO 請(qǐng)求在這里被合并(相鄰的小 IO 合并成大 IO)、排序、調(diào)度。blk-mq(多隊(duì)列塊層)是 6.x 內(nèi)核的默認(rèn)架構(gòu),每個(gè) CPU 核心有獨(dú)立的軟件隊(duì)列,減少了鎖競(jìng)爭。

設(shè)備驅(qū)動(dòng)和物理設(shè)備:NVMe 設(shè)備有自己的硬件多隊(duì)列(通常 64 個(gè)隊(duì)列,每隊(duì)列 64K 深度),SATA SSD 只有單隊(duì)列(NCQ 深度 32)。這個(gè)差異直接影響并發(fā) IO 性能。

2.2 IO 調(diào)度器詳解

內(nèi)核 6.x 提供了四種 IO 調(diào)度器,針對(duì)不同設(shè)備類型選擇合適的調(diào)度器對(duì)性能影響很大。

# 查看當(dāng)前磁盤使用的調(diào)度器(方括號(hào)標(biāo)記的是當(dāng)前生效的)
cat /sys/block/sda/queue/scheduler
# 輸出示例:[mq-deadline] kyber bfq none

# 運(yùn)行時(shí)切換調(diào)度器(立即生效,不需要重啟)
echo"bfq"> /sys/block/sda/queue/scheduler

四種調(diào)度器的選型策略:

調(diào)度器 適用場(chǎng)景 核心機(jī)制 推薦設(shè)備
none NVMe SSD 不做任何調(diào)度,直接下發(fā)到硬件隊(duì)列 NVMe SSD(硬件自帶調(diào)度)
mq-deadline 通用場(chǎng)景 按截止時(shí)間排序,防止請(qǐng)求餓死,讀優(yōu)先于寫 SATA SSD、HDD、虛擬機(jī)云盤
bfq 桌面/混合負(fù)載 按進(jìn)程公平分配 IO 帶寬,類似 CPU 的 CFS HDD、需要 IO 公平性的多租戶場(chǎng)景
kyber 低延遲 SSD 基于目標(biāo)延遲的輕量級(jí)調(diào)度,自動(dòng)調(diào)節(jié)隊(duì)列深度 高性能 SATA SSD

選型建議:NVMe SSD 直接用none,不要畫蛇添足加調(diào)度器。HDD 用mq-deadline保證讀延遲可控。多用戶共享 HDD 的場(chǎng)景(比如編譯服務(wù)器)用bfq防止某個(gè)進(jìn)程獨(dú)占 IO 帶寬。kyber在實(shí)際生產(chǎn)中用得不多,它的自適應(yīng)機(jī)制在負(fù)載波動(dòng)大的場(chǎng)景下表現(xiàn)不夠穩(wěn)定。

# 持久化調(diào)度器配置(udev 規(guī)則)
cat > /etc/udev/rules.d/60-io-scheduler.rules <

2.3 SSD vs HDD 的 IO 特性差異

理解 SSD 和 HDD 的物理特性差異,是正確解讀 IO 指標(biāo)的前提。

特性 HDD SATA SSD NVMe SSD
隨機(jī)讀 IOPS 100-200 30K-90K 200K-1M+
隨機(jī)寫 IOPS 100-200 20K-70K 100K-500K+
順序讀吞吐 150-250 MB/s 500-560 MB/s 3-7 GB/s
順序?qū)懲掏?/td> 150-250 MB/s 400-530 MB/s 2-5 GB/s
平均延遲 5-15ms 0.05-0.1ms 0.01-0.03ms
隊(duì)列深度 1(NCQ=32) 32(NCQ) 64K x 多隊(duì)列
%util 參考意義 高(機(jī)械臂同一時(shí)刻只能服務(wù)一個(gè)位置) 低(內(nèi)部并行度高) 極低(不要看這個(gè)指標(biāo))

這里有一個(gè)非常關(guān)鍵的認(rèn)知:**%util對(duì) SSD 幾乎沒有參考價(jià)值**。HDD 是單通道設(shè)備,%util100% 確實(shí)意味著磁盤忙不過來。但 SSD 內(nèi)部有大量并行通道,%util100% 可能只用了實(shí)際能力的 10%。判斷 SSD 是否到達(dá)瓶頸,應(yīng)該看await(IO 延遲)和實(shí)際 IOPS 是否接近設(shè)備標(biāo)稱值。

三、iostat 輸出深度解讀

iostat 是 IO 排查的第一站,但它的輸出字段很多,不少人只會(huì)看%util,這遠(yuǎn)遠(yuǎn)不夠。

3.1 iostat 基礎(chǔ)用法

# 最常用的命令:每秒刷新一次,顯示擴(kuò)展信息,單位用 MB
# -x 擴(kuò)展模式 -m 單位MB -t 顯示時(shí)間戳 1 間隔1秒
iostat -xmt 1

# 只看特定磁盤
iostat -xmt -d nvme0n1 sda 1

# 看第一次輸出要注意:第一行是系統(tǒng)啟動(dòng)以來的累計(jì)平均值,不是實(shí)時(shí)數(shù)據(jù)
# 從第二行開始才是每秒的實(shí)時(shí)數(shù)據(jù),排查問題時(shí)忽略第一行

3.2 輸出字段逐個(gè)拆解

一條典型的 iostat -x 輸出:

Device r/s  rkB/s  rrqm/s %rrqm r_await rareq-sz w/s  wkB/s  wrqm/s %wrqm w_await wareq-sz d/s dkB/s drqm/s %drqm d_await dareq-sz f/s f_await aqu-sz %util
sda   850.00 13600.0 45.00  5.03  0.85   16.00   320.00 25600.0 120.00 27.27 2.30   80.00  0.00 0.00  0.00  0.00  0.00   0.00   0.00 0.00  1.25  78.40

核心指標(biāo)解讀:

指標(biāo) 含義 怎么看
r/s /w/s 每秒完成的讀/寫請(qǐng)求數(shù)(IOPS) HDD 超過 150 就要警惕,NVMe 到 10 萬都正常
rkB/s /wkB/s 每秒讀/寫的數(shù)據(jù)量(吞吐) 對(duì)比磁盤標(biāo)稱帶寬,接近上限說明帶寬打滿
rrqm/s /wrqm/s 每秒合并的讀/寫請(qǐng)求數(shù) 合并率高說明應(yīng)用的 IO 模式比較友好(順序或相鄰)
r_await /w_await 讀/寫請(qǐng)求的平均耗時(shí)(ms),包含隊(duì)列等待+設(shè)備服務(wù)時(shí)間 最重要的延遲指標(biāo) 。HDD 正常 5-15ms,SSD 正常 0.05-0.5ms
aqu-sz 平均請(qǐng)求隊(duì)列長度 隊(duì)列長說明設(shè)備處理不過來,請(qǐng)求在排隊(duì)
%util 設(shè)備繁忙時(shí)間百分比 HDD 有參考意義,SSD 參考價(jià)值低(前面解釋過)
rareq-sz /wareq-sz 平均請(qǐng)求大小(KB) 判斷 IO 模式:4-8KB 是典型隨機(jī) IO,128KB+ 是順序 IO

已廢棄的 svctm:老版本 iostat 有svctm(設(shè)備服務(wù)時(shí)間)字段,sysstat 12.x 已經(jīng)標(biāo)記為不可靠并計(jì)劃移除。這個(gè)值是用%util / (r/s + w/s)反算出來的,在多隊(duì)列設(shè)備上完全失真。不要再用svctm做任何判斷。

3.3 iostat 實(shí)戰(zhàn)判斷模板

# 場(chǎng)景判斷速查:
# 1. await 高 + aqu-sz 高 + %util 高 → 磁盤確實(shí)忙不過來(HDD 常見)
# 2. await 高 + aqu-sz 低 + %util 低 → 單個(gè) IO 慢,可能是磁盤硬件問題或 RAID 降級(jí)
# 3. await 正常 + w/s 極高 + wkB/s 低 → 大量小寫入,考慮合并 IO 或調(diào)大 dirty ratio
# 4. rrqm/s 接近 0 + rareq-sz 很小 → 純隨機(jī)讀,Page Cache 沒起作用
# 5. w_await 遠(yuǎn)高于 r_await → 寫入瓶頸,檢查 fsync 頻率和 journal 模式

3.4 用 sar 看 IO 歷史趨勢(shì)

iostat 只能看實(shí)時(shí)數(shù)據(jù),要回溯歷史得靠 sar。sysstat 默認(rèn)每 10 分鐘采集一次數(shù)據(jù),保存在/var/log/sysstat/或/var/log/sa/下。

# 查看今天的磁盤 IO 歷史(-d 磁盤統(tǒng)計(jì),-p 顯示設(shè)備名)
sar -dp 0

# 查看昨天的數(shù)據(jù)
sar -dp -f /var/log/sysstat/sa$(date -d yesterday +%d)

# 查看指定時(shí)間段
sar -dp -s 0200 -e 0400

# 輸出示例:
# 0201 DEV    tps   rkB/s   wkB/s areq-sz aqu-sz await %util
# 0201 sda   1250.00 10000.00 40000.00  40.00  3.50  2.80 92.00
# 0201 sda   120.00  960.00  2400.00  28.00  0.15  1.25 12.00

凌晨 2:10 到 2:20 之間 IO 明顯飆升,tps 從 120 跳到 1250,%util從 12% 到 92%。結(jié)合業(yè)務(wù)日志看這個(gè)時(shí)間段在做什么——大概率是定時(shí)任務(wù)(備份、日志輪轉(zhuǎn)、ETL 作業(yè))。

四、iotop 定位 IO 密集進(jìn)程

iostat 告訴你磁盤整體很忙,但不告訴你是誰在讀寫。這時(shí)候需要 iotop 來定位到具體進(jìn)程。

4.1 iotop 基礎(chǔ)用法

# 需要 root 權(quán)限(依賴內(nèi)核的 taskstats 接口)
# -o 只顯示有 IO 活動(dòng)的進(jìn)程(過濾掉空閑的)
# -P 顯示進(jìn)程而不是線程
# -a 累積模式(顯示自啟動(dòng)以來的累計(jì) IO 量)
sudo iotop -oP

# 推薦使用 iotop-c(C 語言重寫版,性能更好)
# Ubuntu: sudo apt install iotop-c
sudo iotop-c -oP

4.2 iotop 輸出解讀

Total DISK READ:    125.50 M/s | Total DISK WRITE:    42.30 M/s
Actual DISK READ:   125.50 M/s | Actual DISK WRITE:    8.75 M/s
  TID PRIO USER   DISK READ DISK WRITE SWAPIN   IO>  COMMAND
 12847 be/4 mysql   98.20 M/s  5.60 M/s  0.00 % 82.35 % mysqld --defaults-file=/etc/mysql/my.cnf
 3021 be/4 root   22.10 M/s  0.00 B/s  0.00 % 15.20 % tar czf /backup/db-20260206.tar.gz /var/lib/mysql
  891 be/4 elastic  5.20 M/s  36.70 M/s  0.00 %  8.50 % java -Xms16g ... elasticsearch

幾個(gè)關(guān)鍵信息:

Total DISK READ/WRITE:所有進(jìn)程請(qǐng)求的 IO 總量(經(jīng)過 Page Cache 之前)

Actual DISK READ/WRITE:實(shí)際落到磁盤的 IO 量。Actual WRITE 遠(yuǎn)小于 Total WRITE 是正常的,因?yàn)閷懭胂鹊?Page Cache,異步刷盤

**IO>**:該進(jìn)程等待 IO 的時(shí)間占比,這個(gè)值高說明進(jìn)程被 IO 阻塞了

PRIO:IO 優(yōu)先級(jí),be/4表示 best-effort 類第 4 級(jí)(默認(rèn)值)

上面的輸出一眼就能看出:mysql 進(jìn)程在瘋狂讀數(shù)據(jù)(98 MB/s),同時(shí)有個(gè) tar 備份任務(wù)也在讀(22 MB/s)。兩個(gè)大讀取任務(wù)疊加,磁盤帶寬被打滿了。

4.3 用 ionice 調(diào)整 IO 優(yōu)先級(jí)

找到了搗亂的進(jìn)程,如果不能直接 kill,可以用 ionice 降低它的 IO 優(yōu)先級(jí):

# IO 調(diào)度類:
# 1 = Realtime(實(shí)時(shí),慎用)
# 2 = Best-effort(默認(rèn),0-7 級(jí),數(shù)字越小優(yōu)先級(jí)越高)
# 3 = Idle(空閑時(shí)才執(zhí)行,適合備份任務(wù))

# 把備份進(jìn)程降到 Idle 級(jí)別(只在磁盤空閑時(shí)才給它 IO)
sudo ionice -c 3 -p 3021

# 啟動(dòng)備份任務(wù)時(shí)直接指定低優(yōu)先級(jí)
sudo ionice -c 3 nice -n 19 tar czf /backup/db-20260206.tar.gz /var/lib/mysql

# 注意:ionice 只在 bfq 和 mq-deadline 調(diào)度器下生效
# none 調(diào)度器(NVMe 默認(rèn))不支持 IO 優(yōu)先級(jí)

4.4 pidstat 補(bǔ)充進(jìn)程級(jí) IO 統(tǒng)計(jì)

iotop 是交互式的,不方便腳本化采集。pidstat 可以按固定間隔輸出進(jìn)程 IO 數(shù)據(jù):

# -d 顯示 IO 統(tǒng)計(jì) 1 每秒采集 10 采集10次
pidstat -d 1 10

# 只看特定進(jìn)程
pidstat -d -p 12847 1

# 輸出示例:
# Time   UID PID  kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
# 1501 999 12847 98200.00 5600.00  800.00   45  mysqld

kB_ccwr/s是被取消的寫入量(寫入 Page Cache 后又被覆蓋,沒有實(shí)際落盤),iodelay是進(jìn)程因?yàn)?IO 等待而被延遲的 tick 數(shù)。

五、blktrace + btt 深度分析

iostat 和 iotop 能解決 80% 的 IO 問題,但遇到復(fù)雜場(chǎng)景——比如需要知道 IO 請(qǐng)求在塊層各個(gè)階段分別花了多少時(shí)間——就需要 blktrace 出場(chǎng)了。

5.1 blktrace 工作原理

blktrace 在內(nèi)核的塊層埋了追蹤點(diǎn),記錄每個(gè) IO 請(qǐng)求的完整生命周期:

Q (Queued)   → 請(qǐng)求進(jìn)入塊層隊(duì)列
G (Get request) → 分配 request 結(jié)構(gòu)體
M (Merged)   → 與已有請(qǐng)求合并
I (Inserted)  → 插入調(diào)度器隊(duì)列
D (Dispatched) → 下發(fā)到設(shè)備驅(qū)動(dòng)
C (Completed)  → 設(shè)備完成 IO

每個(gè)階段之間的時(shí)間差就是該階段的耗時(shí)。Q→C是總耗時(shí),D→C是設(shè)備實(shí)際服務(wù)時(shí)間,Q→D是在軟件層排隊(duì)和調(diào)度的時(shí)間。

5.2 blktrace 實(shí)戰(zhàn)

# 采集 sda 的塊層追蹤數(shù)據(jù),持續(xù) 10 秒
sudo blktrace -d /dev/sda -w 10 -o trace

# 會(huì)生成 trace.blktrace.0, trace.blktrace.1 ... 每個(gè) CPU 一個(gè)文件

# 用 blkparse 解析成可讀格式
blkparse -i trace -o trace.txt

# 輸出示例(每行一個(gè)事件):
# 8,0 1 1 0.000000000 12847 Q R 123456 + 8 [mysqld]
# 8,0 1 2 0.000001200 12847 G R 123456 + 8 [mysqld]
# 8,0 1 3 0.000002500 12847 I R 123456 + 8 [mysqld]
# 8,0 1 4 0.000015000 12847 D R 123456 + 8 [mysqld]
# 8,0 1 5 0.000850000   0  C R 123456 + 8 [0]
# 解讀:mysqld 發(fā)起了一個(gè)讀請(qǐng)求,扇區(qū) 123456 開始讀 8 個(gè)扇區(qū)(4KB)
# Q→D 排隊(duì) 15us,D→C 設(shè)備服務(wù) 835us,總耗時(shí) 850us

5.3 btt 統(tǒng)計(jì)分析

逐行看 blkparse 輸出不現(xiàn)實(shí),btt 工具可以自動(dòng)統(tǒng)計(jì)各階段的延遲分布:

# 用 btt 分析(需要先用 blkparse 生成二進(jìn)制格式)
blkparse -i trace -d trace.bin
btt -i trace.bin

# btt 輸出的關(guān)鍵段落:

# ==================== All Devices ====================
#       ALL      MIN      AVG      MAX      N
# --------------- ------------- ------------- ------------- -----------
# Q2C        0.000085000  0.001250000  0.025000000    12847
# Q2D        0.000005000  0.000018000  0.000350000    12847
# D2C        0.000080000  0.001232000  0.024800000    12847

# Q2C = 總延遲(隊(duì)列到完成)
# Q2D = 軟件層延遲(隊(duì)列到下發(fā))
# D2C = 硬件層延遲(下發(fā)到完成)

上面的數(shù)據(jù)說明:平均總延遲 1.25ms,其中軟件層只占 0.018ms,硬件層占 1.232ms。瓶頸在設(shè)備本身,不在內(nèi)核調(diào)度。如果反過來 Q2D 很大而 D2C 很小,說明是調(diào)度器或隊(duì)列配置有問題。

5.4 iowatcher 可視化

blktrace 的數(shù)據(jù)還可以用 iowatcher 生成可視化圖表,直觀展示 IO 模式:

# 安裝 iowatcher
sudo apt install iowatcher

# 生成 SVG 圖表
iowatcher -t trace -o io-pattern.svg

# 圖表包含:IOPS 時(shí)間線、吞吐時(shí)間線、IO 延遲分布、IO 偏移量分布(可以看出是順序還是隨機(jī))

六、fio 磁盤性能基準(zhǔn)測(cè)試

排查 IO 問題時(shí)經(jīng)常需要回答一個(gè)基本問題:這塊磁盤到底能跑多快?是磁盤本身性能不行,還是應(yīng)用的 IO 模式有問題?fio 是回答這個(gè)問題的標(biāo)準(zhǔn)工具。

6.1 fio 核心參數(shù)

# 安裝 fio
sudo apt install fio  # Debian/Ubuntu
sudo dnf install fio  # RHEL/Fedora

fio 的參數(shù)很多,但核心就這幾個(gè):

參數(shù) 含義 常用值
--rw IO 模式 read /write/randread/randwrite/randrw
--bs 塊大小 4k (數(shù)據(jù)庫隨機(jī)IO)、128k/1m(順序IO)
--iodepth 隊(duì)列深度 HDD 用 1-4,SATA SSD 用 32,NVMe 用 64-128
--ioengine IO 引擎 libaio (Linux AIO)、io_uring(推薦,內(nèi)核 6.x)
--numjobs 并發(fā)任務(wù)數(shù) 通常 1-4,測(cè)多隊(duì)列性能時(shí)增大
--size 測(cè)試文件大小 至少是內(nèi)存的 2 倍,避免 Page Cache 干擾
--direct 繞過 Page Cache 1 (基準(zhǔn)測(cè)試必須開啟)
--runtime 運(yùn)行時(shí)長 60-120 秒,太短數(shù)據(jù)不穩(wěn)定

6.2 標(biāo)準(zhǔn)測(cè)試場(chǎng)景

# 場(chǎng)景1:隨機(jī)讀 IOPS(模擬數(shù)據(jù)庫查詢)
fio --name=rand-read --ioengine=io_uring --rw=randread 
  --bs=4k --iodepth=64 --numjobs=4 --size=4G 
  --direct=1 --runtime=60 --group_reporting 
  --filename=/dev/nvme0n1 # 注意:直接測(cè)裸設(shè)備會(huì)銷毀數(shù)據(jù)!測(cè)試用文件更安全

# 更安全的方式:在文件系統(tǒng)上測(cè)試
fio --name=rand-read --ioengine=io_uring --rw=randread 
  --bs=4k --iodepth=64 --numjobs=4 --size=4G 
  --direct=1 --runtime=60 --group_reporting 
  --directory=/mnt/test

# 場(chǎng)景2:隨機(jī)寫 IOPS(模擬數(shù)據(jù)庫寫入)
fio --name=rand-write --ioengine=io_uring --rw=randwrite 
  --bs=4k --iodepth=64 --numjobs=4 --size=4G 
  --direct=1 --runtime=60 --group_reporting 
  --directory=/mnt/test

# 場(chǎng)景3:順序讀吞吐(模擬大文件掃描、備份)
fio --name=seq-read --ioengine=io_uring --rw=read
  --bs=1m --iodepth=16 --numjobs=1 --size=8G 
  --direct=1 --runtime=60 --group_reporting 
  --directory=/mnt/test

# 場(chǎng)景4:混合隨機(jī)讀寫 7:3(模擬 OLTP 數(shù)據(jù)庫)
fio --name=mixed-rw --ioengine=io_uring --rw=randrw --rwmixread=70 
  --bs=4k --iodepth=32 --numjobs=4 --size=4G 
  --direct=1 --runtime=60 --group_reporting 
  --directory=/mnt/test

6.3 fio 輸出解讀

rand-read: (groupid=0,jobs=4): err= 0: pid=5678
read: IOPS=185.2k, BW=723MiB/s (758MB/s)
  slat (nsec): min=1200, max=85000, avg=2850.00, stdev=1200.00
  clat (usec): min=45, max=12500, avg=1350.00, stdev=680.00
  lat (usec): min=48, max=12520, avg=1353.00, stdev=681.00
  clat percentiles (usec):
  | 1.00th=[ 120], 5.00th=[ 245], 10.00th=[ 400],
  | 50.00th=[ 1150], 90.00th=[ 2350], 95.00th=[ 2900],
  | 99.00th=[ 4500], 99.50th=[ 5800], 99.99th=[10800]
 bw ( KiB/s): min=680000, max=760000, per=100.00%, avg=740800.00
 iops    : min=170000, max=190000, avg=185200.00

關(guān)鍵指標(biāo):

IOPS=185.2k:每秒 18.5 萬次隨機(jī)讀,這是一塊性能不錯(cuò)的 NVMe SSD

slatsubmission latency):提交延遲,從應(yīng)用發(fā)起到進(jìn)入內(nèi)核,通常在微秒級(jí)

clat(completion latency):完成延遲,從進(jìn)入內(nèi)核到 IO 完成,這是最關(guān)注的指標(biāo)

lat:總延遲 = slat + clat

clat percentiles:延遲分位數(shù),P99=4.5ms 說明 99% 的請(qǐng)求在 4.5ms 內(nèi)完成。關(guān)注 P99 和 P99.9,平均值會(huì)掩蓋長尾延遲

6.4 io_uring vs libaio

內(nèi)核 6.x 環(huán)境下強(qiáng)烈推薦使用io_uring引擎替代傳統(tǒng)的libaio:

# 對(duì)比測(cè)試:同樣參數(shù),只換引擎
# libaio
fio --name=aio-test --ioengine=libaio --rw=randread 
  --bs=4k --iodepth=128 --numjobs=1 --size=4G 
  --direct=1 --runtime=30 --directory=/mnt/test

# io_uring
fio --name=uring-test --ioengine=io_uring --rw=randread 
  --bs=4k --iodepth=128 --numjobs=1 --size=4G 
  --direct=1 --runtime=30 --directory=/mnt/test

io_uring 的優(yōu)勢(shì)在于減少了系統(tǒng)調(diào)用次數(shù)(通過共享內(nèi)存的提交/完成隊(duì)列),在高 IOPS 場(chǎng)景下能比 libaio 高出 10%-30% 的性能。現(xiàn)代數(shù)據(jù)庫(如 PostgreSQL 16+、RocksDB)已經(jīng)原生支持 io_uring。

七、文件系統(tǒng)選擇

文件系統(tǒng)是 IO 棧中直接影響性能的一層,選錯(cuò)文件系統(tǒng)可能導(dǎo)致性能差距達(dá)到 2-3 倍。

7.1 ext4 / xfs / btrfs 對(duì)比

特性 ext4 xfs btrfs
最大文件系統(tǒng) 1 EB 8 EB 16 EB
最大單文件 16 TB 8 EB 16 EB
元數(shù)據(jù)日志 有序/回寫 有序 CoW(無傳統(tǒng)日志)
在線擴(kuò)容 支持 支持 支持
在線縮容 支持 不支持 支持
快照 不支持 不支持 原生支持
透明壓縮 不支持 不支持 支持(zstd/lzo)
小文件性能 優(yōu)秀 良好 一般
大文件順序?qū)?/td> 良好 優(yōu)秀 良好
并發(fā)寫入 一般(單 journal) 優(yōu)秀(延遲分配) 良好
生產(chǎn)穩(wěn)定性 極高 極高 高(6.x 內(nèi)核已成熟)

選型建議

數(shù)據(jù)庫服務(wù)器(MySQL/PostgreSQL):xfs。延遲分配和優(yōu)秀的并發(fā)寫入性能對(duì)數(shù)據(jù)庫友好,RHEL 默認(rèn)文件系統(tǒng)

通用 Linux 服務(wù)器:ext4。最穩(wěn)定、最成熟、調(diào)優(yōu)資料最多,Ubuntu 默認(rèn)文件系統(tǒng)

需要快照/壓縮的場(chǎng)景(日志存儲(chǔ)、容器存儲(chǔ)):btrfs。透明壓縮可以節(jié)省 30%-50% 的磁盤空間,快照功能方便備份

Kubernetes 節(jié)點(diǎn):xfs。containerd/CRI-O 的 overlayfs 在 xfs 上表現(xiàn)更好

7.2 文件系統(tǒng)掛載參數(shù)調(diào)優(yōu)

# ext4 高性能掛載參數(shù)
mount -o noatime,nodiratime,barrier=0,data=writeback /dev/sda1 /data
# noatime: 不更新訪問時(shí)間戳,減少寫入
# nodiratime: 不更新目錄訪問時(shí)間
# barrier=0: 關(guān)閉寫屏障(僅在有 BBU 的 RAID 卡上使用,否則斷電丟數(shù)據(jù))
# data=writeback: 元數(shù)據(jù)日志模式,比默認(rèn)的 ordered 快但斷電風(fēng)險(xiǎn)略高

# xfs 高性能掛載參數(shù)
mount -o noatime,logbufs=8,logbsize=256k /dev/sda1 /data
# logbufs=8: 增大日志緩沖區(qū)數(shù)量
# logbsize=256k: 增大日志緩沖區(qū)大小

# /etc/fstab 持久化配置
/dev/nvme0n1p1 /data xfs defaults,noatime,logbufs=8,logbsize=256k 0 2

八、IO 性能調(diào)優(yōu)

8.1 readahead 預(yù)讀調(diào)優(yōu)

預(yù)讀是內(nèi)核在檢測(cè)到順序讀模式時(shí),提前讀取后續(xù)數(shù)據(jù)到 Page Cache 的機(jī)制。對(duì)順序讀密集的場(chǎng)景(日志分析、數(shù)據(jù)導(dǎo)出)效果顯著。

# 查看當(dāng)前預(yù)讀值(單位:512字節(jié)扇區(qū),默認(rèn) 256 = 128KB)
blockdev --getra /dev/sda

# 調(diào)大預(yù)讀值(適合順序讀場(chǎng)景,如 Kafka、HDFS)
sudo blockdev --setra 2048 /dev/sda # 1MB 預(yù)讀

# 調(diào)小預(yù)讀值(適合純隨機(jī)讀場(chǎng)景,如數(shù)據(jù)庫 OLTP)
sudo blockdev --setra 64 /dev/sda  # 32KB 預(yù)讀

# 持久化配置(udev 規(guī)則)
echo'ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{bdi/read_ahead_kb}="1024"'
  > /etc/udev/rules.d/61-readahead.rules

8.2 dirty ratio 臟頁參數(shù)調(diào)優(yōu)

臟頁參數(shù)控制 Page Cache 中臟數(shù)據(jù)的刷盤策略,直接影響寫入性能和數(shù)據(jù)安全性。

# 查看當(dāng)前臟頁參數(shù)
sysctl vm.dirty_ratio vm.dirty_background_ratio vm.dirty_expire_centisecs vm.dirty_writeback_centisecs

# 參數(shù)說明:
# vm.dirty_ratio = 20      # 臟頁占內(nèi)存 20% 時(shí),寫入進(jìn)程被阻塞,同步刷盤(硬上限)
# vm.dirty_background_ratio = 10 # 臟頁占內(nèi)存 10% 時(shí),后臺(tái)線程開始異步刷盤(軟上限)
# vm.dirty_expire_centisecs = 3000 # 臟頁超過 30 秒必須刷盤
# vm.dirty_writeback_centisecs = 500 # 后臺(tái)刷盤線程每 5 秒喚醒一次

不同場(chǎng)景的調(diào)優(yōu)策略

# 數(shù)據(jù)庫服務(wù)器(低延遲優(yōu)先,減少突發(fā)刷盤導(dǎo)致的延遲毛刺)
sysctl -w vm.dirty_ratio=5
sysctl -w vm.dirty_background_ratio=2
sysctl -w vm.dirty_expire_centisecs=1000
sysctl -w vm.dirty_writeback_centisecs=100

# 日志/流式寫入服務(wù)器(吞吐優(yōu)先,允許更多臟頁緩沖)
sysctl -w vm.dirty_ratio=40
sysctl -w vm.dirty_background_ratio=20
sysctl -w vm.dirty_expire_centisecs=6000
sysctl -w vm.dirty_writeback_centisecs=500

# 持久化到 /etc/sysctl.d/60-io-tuning.conf
cat > /etc/sysctl.d/60-io-tuning.conf <

8.3 隊(duì)列深度與 nr_requests 調(diào)優(yōu)

# 查看塊設(shè)備隊(duì)列深度
cat /sys/block/sda/queue/nr_requests
# 默認(rèn)值通常是 256

# NVMe 設(shè)備的硬件隊(duì)列深度
cat /sys/block/nvme0n1/queue/nr_requests

# 對(duì)于高并發(fā) IO 場(chǎng)景,可以適當(dāng)增大隊(duì)列深度
echo1024 > /sys/block/sda/queue/nr_requests

# 查看當(dāng)前 IO 合并策略
cat /sys/block/sda/queue/nomerges
# 0 = 允許合并(默認(rèn)) 1 = 禁止前向合并 2 = 完全禁止合并
# 純隨機(jī) IO 場(chǎng)景可以設(shè)為 2,省去合并檢查的開銷

8.4 cgroup v2 IO 限制

在多租戶或容器環(huán)境下,用 cgroup v2 的 io 控制器限制進(jìn)程的 IO 帶寬和 IOPS:

# 查看設(shè)備號(hào)(major:minor)
ls -l /dev/sda
# brw-rw---- 1 root disk 8, 0 ... → 設(shè)備號(hào) 8:0

# 創(chuàng)建 cgroup 并設(shè)置 IO 限制
mkdir -p /sys/fs/cgroup/backup-jobs
echo"+io"> /sys/fs/cgroup/backup-jobs/cgroup.subtree_control

# 限制 sda 上的讀寫帶寬為 50MB/s,IOPS 為 1000
echo"8:0 rbps=52428800 wbps=52428800 riops=1000 wiops=1000"
  > /sys/fs/cgroup/backup-jobs/io.max

# 把備份進(jìn)程加入這個(gè) cgroup
echo$BACKUP_PID> /sys/fs/cgroup/backup-jobs/cgroup.procs

# Kubernetes 中通過 Pod 的 resources 或 annotation 配置
# 也可以用 io.latency 控制器設(shè)置延遲目標(biāo)
echo"8:0 target=5000"> /sys/fs/cgroup/db-workload/io.latency
# 保證 db-workload 組的 IO 延遲不超過 5ms,其他組讓路

九、常見 IO 問題排查案例

9.1 案例一:凌晨定時(shí)任務(wù)導(dǎo)致數(shù)據(jù)庫延遲飆升

現(xiàn)象:每天凌晨 230,MySQL 慢查詢數(shù)量暴增 10 倍,await從 0.5ms 飆到 15ms。

排查過程

# 1. 先看 iostat 確認(rèn) IO 確實(shí)有問題
iostat -xmt 1
# 發(fā)現(xiàn) w_await 從 0.5ms 漲到 15ms,wkB/s 從 20MB/s 漲到 180MB/s

# 2. iotop 找出誰在寫
sudo iotop -oP
# 發(fā)現(xiàn)兩個(gè)大戶:
# mysqld   → 20MB/s 寫入(正常業(yè)務(wù))
# rsync    → 160MB/s 讀?。▊浞萑蝿?wù)在全量拷貝數(shù)據(jù)目錄)

# 3. 確認(rèn) rsync 是定時(shí)任務(wù)觸發(fā)的
ps aux | grep rsync
# root 5432 rsync -avz /var/lib/mysql/ backup-server:/backup/mysql/

# 4. rsync 的大量順序讀把磁盤帶寬吃滿,MySQL 的隨機(jī) IO 被擠壓

解決方案

# 方案1:用 ionice 降低備份任務(wù)優(yōu)先級(jí)
ionice -c 3 nice -n 19 rsync -avz /var/lib/mysql/ backup-server:/backup/mysql/

# 方案2:用 cgroup v2 限制備份任務(wù)的 IO 帶寬
echo"8:0 rbps=52428800 wbps=52428800"> /sys/fs/cgroup/backup/io.max

# 方案3:用 rsync 的 --bwlimit 限制傳輸速率
rsync -avz --bwlimit=50000 /var/lib/mysql/ backup-server:/backup/mysql/
# --bwlimit 單位是 KB/s,50000 = 50MB/s

9.2 案例二:ext4 journal 寫放大導(dǎo)致寫入性能驟降

現(xiàn)象:一臺(tái)跑 Elasticsearch 的機(jī)器,寫入吞吐突然從 200MB/s 降到 40MB/s,iostat 顯示w/s很高但wareq-sz只有 4KB。

排查過程

# 1. iostat 看寫入模式
iostat -xmt -d sda 1
# w/s=8500 wkB/s=34000 wareq-sz=4.0 w_await=3.5 %util=98

# 大量 4KB 小寫入,這不像 ES 的正常行為(ES 的 segment merge 是大塊順序?qū)懀?
# 2. 用 blktrace 看寫入來源
sudo blktrace -d /dev/sda -w 5 -o journal-trace
blkparse -i journal-trace | grep"W"| awk'{print $NF}'| sort | uniq -c | sort -rn | head
# 發(fā)現(xiàn)大量寫入來自 [jbd2/sda1-8],這是 ext4 的 journal 線程

# 3. 檢查文件系統(tǒng) journal 模式
tune2fs -l /dev/sda1 | grep"Journal"
# Default mount options: journal_data
# journal_data 模式會(huì)把所有數(shù)據(jù)都寫一遍 journal,寫放大 2 倍!

解決方案

# 切換到 ordered 模式(只對(duì)元數(shù)據(jù)做 journal,數(shù)據(jù)直接寫)
sudo mount -o remount,data=ordered /data

# 或者在 /etc/fstab 中修改
/dev/sda1 /data ext4 defaults,noatime,data=ordered 0 2

# 如果是 ES 這種自己管理數(shù)據(jù)一致性的應(yīng)用,甚至可以用 writeback 模式
# 但要確保有 UPS 或 BBU,否則斷電可能丟數(shù)據(jù)

9.3 案例三:NVMe SSD %util 100% 但實(shí)際遠(yuǎn)未飽和

現(xiàn)象:監(jiān)控告警 NVMe 磁盤%util持續(xù) 100%,但業(yè)務(wù)沒有感知到任何延遲。

排查過程

# 1. iostat 看詳細(xì)指標(biāo)
iostat -xmt -d nvme0n1 1
# r/s=45000 rkB/s=180000 r_await=0.08 aqu-sz=3.6 %util=100

# r_await 只有 0.08ms(80 微秒),完全正常
# IOPS 45K,這塊 NVMe 標(biāo)稱能跑 500K IOPS,遠(yuǎn)沒到極限

# 2. 這是 %util 計(jì)算方式的問題
# %util = (IO 請(qǐng)求數(shù) * 每次 IO 耗時(shí)) / 采樣間隔
# 當(dāng)并發(fā) IO 足夠多時(shí),即使每個(gè) IO 很快,%util 也會(huì)算到 100%
# 對(duì)于多隊(duì)列設(shè)備,%util 100% 不代表設(shè)備飽和

結(jié)論:這是一個(gè)誤告警。對(duì) NVMe SSD 應(yīng)該基于await和 IOPS 來判斷是否飽和,而不是%util。監(jiān)控告警規(guī)則需要調(diào)整:

# Prometheus 告警規(guī)則(修正版)
# 不再用 %util 告警 NVMe 設(shè)備,改用 await
-alert:DiskIOHighLatency
expr:|
  rate(node_disk_io_time_weighted_seconds_total[5m])
  / rate(node_disk_io_time_seconds_total[5m]) > 0.005
for:5m
labels:
 severity:warning
annotations:
 summary:"磁盤 IO 平均延遲超過 5ms"

十、bpftrace 追蹤 IO 延遲

iostat 給的是平均值,blktrace 數(shù)據(jù)量太大不適合長期運(yùn)行。bpftrace 可以用極低的開銷實(shí)時(shí)追蹤 IO 延遲分布,是定位長尾延遲問題的利器。

10.1 biolatency:IO 延遲直方圖

# bcc-tools 自帶的 biolatency 腳本(最簡單的用法)
sudo biolatency-bpfcc -D 1
# -D 按磁盤分別統(tǒng)計(jì) 1 每秒輸出一次

# 輸出示例:
# disk = nvme0n1
#   usecs        : count  distribution
#     0 -> 1     : 0    |                    |
#     2 -> 3     : 0    |                    |
#     4 -> 7     : 125   |**                   |
#     8 -> 15     : 2840   |****************************************|
#     16 -> 31     : 1950   |***************************       |
#     32 -> 63     : 680   |*********                |
#     64 -> 127    : 245   |***                   |
#    128 -> 255    : 42    |                    |
#    256 -> 511    : 8    |                    |
#    512 -> 1023    : 3    |                    |
#    1024 -> 2047    : 1    |                    |

# 大部分 IO 在 8-31 微秒完成,但有少量請(qǐng)求到了毫秒級(jí)——這就是長尾延遲

10.2 自定義 bpftrace 腳本:按進(jìn)程追蹤 IO 延遲

biolatency 只能看全局分布,如果要按進(jìn)程區(qū)分,需要自己寫 bpftrace 腳本:

# 保存為 io-latency-by-process.bt
sudo bpftrace -e'
tracepointblock_rq_issue
{
  @start[args->dev, args->sector] = nsecs;
  @comm[args->dev, args->sector] = comm;
}

tracepointblock_rq_complete
/@start[args->dev, args->sector]/
{
  $lat = (nsecs - @start[args->dev, args->sector]) / 1000; // 轉(zhuǎn)換為微秒
  @latency[@comm[args->dev, args->sector]] = hist($lat);
  delete(@start[args->dev, args->sector]);
  delete(@comm[args->dev, args->sector]);
}

END
{
  clear(@start);
  clear(@comm);
}
'

# 輸出會(huì)按進(jìn)程名分別顯示延遲直方圖:
# @latency[mysqld]:
# [8, 16)  1250 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
# [16, 32)  680 |@@@@@@@@@@@@@@@@@@@@@          |
# ...
# @latency[rsync]:
# [128, 256) 420 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
# [256, 512) 380 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@  |
# ...

10.3 biosnoop:逐條追蹤 IO 請(qǐng)求

當(dāng)需要看每一條 IO 請(qǐng)求的詳細(xì)信息時(shí),用 biosnoop:

# 追蹤所有 IO 請(qǐng)求,顯示進(jìn)程名、延遲、扇區(qū)等
sudo biosnoop-bpfcc -d nvme0n1

# 輸出示例:
# TIME(s) COMM     PID  DISK   T SECTOR    BYTES LAT(ms)
# 0.000  mysqld    12847 nvme0n1  R 12345678   4096  0.08
# 0.001  mysqld    12847 nvme0n1  R 12345686   4096  0.09
# 0.003  jbd2/sda1-8 891  nvme0n1  W 98765432   16384 0.15
# 0.850  rsync    5432 nvme0n1  R 55555555   131072 0.12

# 只看延遲超過 1ms 的慢 IO
sudo biosnoop-bpfcc -d nvme0n1 -Q | awk'$NF > 1.0'

10.4 ext4slower / xfs_slower:文件系統(tǒng)級(jí)慢 IO 追蹤

有時(shí)候塊設(shè)備層延遲正常,但文件系統(tǒng)層有額外開銷(鎖競(jìng)爭、journal 等待)。bcc-tools 提供了文件系統(tǒng)級(jí)別的慢操作追蹤:

# 追蹤 ext4 上超過 1ms 的操作
sudo ext4slower-bpfcc 1

# 追蹤 xfs 上超過 1ms 的操作
sudo xfsslower-bpfcc 1

# 輸出示例:
# TIME   COMM     PID  T BYTES  OFF_KB  LAT(ms) FILENAME
# 1501 mysqld    12847 R 16384  1024   2.35  ibdata1
# 1501 mysqld    12847 S 0    0    5.80  ib_logfile0
# T 列:R=read W=write O=open S=fsync
# fsync 延遲 5.8ms,這可能是 journal 寫入導(dǎo)致的

這個(gè)工具能直接關(guān)聯(lián)到文件名,比 biosnoop 更容易定位到具體是哪個(gè)文件的 IO 有問題。

十一、IO 排查流程總結(jié)

11.1 排查決策樹

系統(tǒng)卡頓/業(yè)務(wù)超時(shí)
 |
 v
top 看 %wa (iowait) ──── 低 → 不是 IO 問題,排查 CPU/內(nèi)存/網(wǎng)絡(luò)
 |
 高
 v
iostat -xmt 1 ──── await 正常 → 可能是應(yīng)用層阻塞,不是磁盤瓶頸
 |
 await 高
 v
判斷設(shè)備類型 ──── NVMe → 看 await + IOPS,忽略 %util
 |        HDD → %util + await + aqu-sz 綜合判斷
 v
iotop -oP ──── 找到 IO 大戶進(jìn)程
 |
 v
分析 IO 模式 ──── wareq-sz/rareq-sz 小(4-8KB) → 隨機(jī) IO
 |        wareq-sz/rareq-sz 大(128K+) → 順序 IO
 v
深入分析 ──── blktrace+btt 看各階段延遲
 |      bpftrace 看延遲分布和長尾
 |      fio 做基準(zhǔn)對(duì)比
 v
調(diào)優(yōu)/解決 ──── 調(diào)度器/readahead/dirty ratio/cgroup 限制/硬件升級(jí)

11.2 工具速查表

工具 用途 關(guān)鍵命令 開銷
top 看 iowait 占比 top -d 1 ,按 1 展開核心 極低
iostat 磁盤整體 IOPS/延遲/吞吐 iostat -xmt 1 極低
sar IO 歷史趨勢(shì)回溯 sar -dp -s 02:00 -e 04:00 無(讀歷史數(shù)據(jù))
iotop 定位 IO 密集進(jìn)程 sudo iotop -oP
pidstat 進(jìn)程級(jí) IO 統(tǒng)計(jì)(可腳本化) pidstat -d 1 10 極低
ionice 調(diào)整進(jìn)程 IO 優(yōu)先級(jí) ionice -c 3 -p
blktrace 塊層 IO 請(qǐng)求全生命周期追蹤 blktrace -d /dev/sda -w 10 中(生成大量數(shù)據(jù))
btt blktrace 數(shù)據(jù)統(tǒng)計(jì)分析 btt -i trace.bin 無(離線分析)
fio 磁盤基準(zhǔn)性能測(cè)試 見第六章各場(chǎng)景命令 高(壓測(cè)工具)
biolatency IO 延遲直方圖分布 sudo biolatency-bpfcc -D 1
biosnoop 逐條 IO 請(qǐng)求追蹤 sudo biosnoop-bpfcc -d sda
ext4slower 文件系統(tǒng)級(jí)慢操作追蹤 sudo ext4slower-bpfcc 1

11.3 調(diào)優(yōu)參數(shù)速查

調(diào)優(yōu)項(xiàng) 參數(shù)/文件 推薦值 適用場(chǎng)景
IO 調(diào)度器 /sys/block/*/queue/scheduler NVMe:none,HDD:mq-deadline 所有場(chǎng)景
預(yù)讀大小 blockdev --setra 順序讀: 2048+,隨機(jī)讀: 64 Kafka/HDFS vs 數(shù)據(jù)庫
臟頁硬上限 vm.dirty_ratio 數(shù)據(jù)庫: 5,日志: 40 寫入密集場(chǎng)景
臟頁軟上限 vm.dirty_background_ratio 數(shù)據(jù)庫: 2,日志: 20 寫入密集場(chǎng)景
臟頁過期 vm.dirty_expire_centisecs 數(shù)據(jù)庫: 1000,日志: 6000 寫入密集場(chǎng)景
隊(duì)列深度 /sys/block/*/queue/nr_requests 高并發(fā): 1024,默認(rèn): 256 高 IOPS 場(chǎng)景
IO 合并 /sys/block/*/queue/nomerges 隨機(jī) IO: 2,順序 IO: 0 純隨機(jī) IO 場(chǎng)景
文件系統(tǒng) mount options noatime 必開 所有場(chǎng)景

十二、總結(jié)

12.1 技術(shù)要點(diǎn)回顧

IO 棧認(rèn)知層面:

分層排查是基本功:一個(gè) IO 請(qǐng)求從 VFS 到文件系統(tǒng)、Block Layer、設(shè)備驅(qū)動(dòng)、物理設(shè)備,至少經(jīng)過五層。排查 IO 問題的核心方法論就是逐層定位,而不是上來就調(diào)內(nèi)核參數(shù)碰運(yùn)氣。搞清楚瓶頸在軟件層(Q2D)還是硬件層(D2C),后續(xù)的調(diào)優(yōu)方向完全不同

%util的適用邊界必須搞清楚:這是生產(chǎn)環(huán)境中最高頻的認(rèn)知誤區(qū)。HDD 是單通道設(shè)備,%util100% 確實(shí)意味著飽和;但 SSD 內(nèi)部有大量并行通道,%util100% 可能只用了實(shí)際能力的 10%。NVMe 設(shè)備判斷是否飽和,看await和實(shí)際 IOPS 與標(biāo)稱值的差距,%util直接忽略

await是延遲排查的錨點(diǎn):它包含隊(duì)列等待和設(shè)備服務(wù)兩部分時(shí)間。HDD 正常 5-15ms,SATA SSD 正常 0.05-0.5ms,NVMe 正常 0.01-0.1ms。超出正常范圍就要往下查,低于正常范圍說明磁盤還有余量

svctm已廢棄,不要再用:sysstat 12.x 明確標(biāo)記該字段不可靠,它是用%util反算出來的,在 blk-mq 多隊(duì)列架構(gòu)下完全失真

工具鏈層面:

iostat → iotop → blktrace → bpftrace,四級(jí)遞進(jìn):iostat 回答"磁盤整體忙不忙",iotop 回答"誰在讀寫",blktrace 回答"IO 請(qǐng)求在各階段花了多少時(shí)間",bpftrace 回答"延遲分布長什么樣、長尾在哪里"。每個(gè)工具解決一個(gè)層面的問題,不要指望一個(gè)工具搞定所有事

fio 基準(zhǔn)測(cè)試是調(diào)優(yōu)的前提:不做基準(zhǔn)就調(diào)參數(shù)等于盲調(diào)。先用 fio 的io_uring引擎跑出磁盤在 4K 隨機(jī)讀寫、128K 順序讀寫下的 IOPS 和吞吐上限,再拿業(yè)務(wù)實(shí)際負(fù)載的 iostat 數(shù)據(jù)去對(duì)比,才能判斷是磁盤能力不足還是應(yīng)用 IO 模式有問題

調(diào)優(yōu)參數(shù)層面:

IO 調(diào)度器選型直接影響性能:NVMe 用none(硬件自帶調(diào)度,軟件層不要畫蛇添足),HDD 用mq-deadline(保證讀延遲可控),多租戶共享 HDD 用bfq(按進(jìn)程公平分配帶寬)。用 udev 規(guī)則持久化,不要每次重啟后手動(dòng)設(shè)置

臟頁參數(shù)是寫入延遲毛刺的主因:數(shù)據(jù)庫場(chǎng)景把dirty_ratio調(diào)到 5%、dirty_background_ratio調(diào)到 2%,可以顯著減少突發(fā)刷盤導(dǎo)致的延遲抖動(dòng)。這是最常被忽略但效果最明顯的調(diào)優(yōu)項(xiàng)

readahead 要按場(chǎng)景區(qū)分:Kafka、HDFS 這類順序讀密集的場(chǎng)景調(diào)大到 1MB 以上;MySQL OLTP 這類純隨機(jī)讀場(chǎng)景調(diào)小到 32KB,避免預(yù)讀浪費(fèi)帶寬

cgroup v2 的 io 控制器是多租戶環(huán)境的剛需:io.max做硬限制、io.latency做延遲保障、io.weight做權(quán)重分配,三者配合使用可以在不升級(jí)硬件的前提下解決 IO 爭搶問題

六、總結(jié)

6.2 進(jìn)階學(xué)習(xí)方向

eBPF/bpftrace 存儲(chǔ)觀測(cè)體系:本文用到的 biolatency、biosnoop 只是 bcc-tools 的預(yù)置腳本,實(shí)際生產(chǎn)中經(jīng)常需要自定義追蹤邏輯。bpftrace 支持掛載到block_rq_issue、block_rq_complete等 tracepoint 上,按進(jìn)程、按設(shè)備、按 IO 大小做多維度延遲分布統(tǒng)計(jì)。更進(jìn)一步,可以用 libbpf + CO-RE 編寫常駐的 IO 觀測(cè) daemon,替代 blktrace 實(shí)現(xiàn)低開銷的長期追蹤。Brendan Gregg 的 bpftrace 工具集和 libbpf-bootstrap 項(xiàng)目是兩個(gè)值得深入研究的起點(diǎn)

io_uring 異步 IO 框架:io_uring 通過用戶態(tài)和內(nèi)核態(tài)共享的 SQ(提交隊(duì)列)/CQ(完成隊(duì)列)環(huán)形緩沖區(qū),將系統(tǒng)調(diào)用開銷降到接近零。在高 IOPS 場(chǎng)景下比 libaio 高出 10%-30% 的性能。值得關(guān)注的高級(jí)特性包括:固定緩沖區(qū)(fixed buffers)避免每次 IO 的內(nèi)存注冊(cè)開銷、鏈?zhǔn)教峤唬╨inked SQEs)實(shí)現(xiàn)原子性多步操作、多環(huán)共享(IORING_SETUP_ATTACH_WQ)減少內(nèi)核線程數(shù)。PostgreSQL 16+、RocksDB、SPDK 已經(jīng)原生集成 io_uring,理解其工作機(jī)制對(duì)評(píng)估和調(diào)優(yōu)這些系統(tǒng)的 IO 性能有直接幫助

NVMe 深度優(yōu)化:NVMe 設(shè)備的性能調(diào)優(yōu)遠(yuǎn)不止選個(gè)none調(diào)度器。硬件多隊(duì)列到 CPU 核心的映射關(guān)系(通過/proc/interrupts和smp_affinity查看和調(diào)整)在 NUMA 架構(gòu)下對(duì)延遲影響顯著——跨 NUMA 節(jié)點(diǎn)訪問 NVMe 隊(duì)列會(huì)增加 30%-50% 的延遲。此外,NVMe 的 namespace 管理、SR-IOV 虛擬化直通、CMB(Controller Memory Buffer)、ZNS(Zoned Namespace)等特性在大規(guī)模存儲(chǔ)集群中逐漸落地,nvme-cli工具集是管理和診斷 NVMe 設(shè)備的必備技能

存儲(chǔ)棧全鏈路可觀測(cè)性建設(shè):把 iostat/sar 的指標(biāo)接入 Prometheus(通過 node_exporter 的 diskstats collector),用 Grafana 構(gòu)建磁盤 IO 大盤,配合本文提到的告警規(guī)則(基于 await 而非 %util),形成從指標(biāo)采集、異常告警到根因定位的完整閉環(huán)。對(duì)于 Kubernetes 環(huán)境,還需要關(guān)注 CSI 驅(qū)動(dòng)層面的 IO 指標(biāo)和 PV/PVC 級(jí)別的 IO 隔離

12.3 參考資料

Linux Block IO Layer- 內(nèi)核官方塊層文檔,理解 blk-mq 架構(gòu)的權(quán)威來源

iostat(1) man page - sysstat- iostat 各字段的精確定義,排查時(shí)遇到指標(biāo)含義不確定直接查這里

BPF Performance Tools (Brendan Gregg)- eBPF 性能工具的系統(tǒng)性參考書,第九章專門講磁盤 IO 追蹤

fio Documentation- fio 官方文檔,參數(shù)說明最全,做基準(zhǔn)測(cè)試前必讀

Linux Storage Stack Diagram- Linux 存儲(chǔ)??梢暬皥D,每個(gè)內(nèi)核版本都有對(duì)應(yīng)的更新版本

io_uring 內(nèi)核文檔- io_uring 的內(nèi)核側(cè)官方文檔,涵蓋 API 設(shè)計(jì)和使用約束

liburing GitHub- io_uring 的用戶態(tài)封裝庫,Jens Axboe 維護(hù),示例代碼是學(xué)習(xí) io_uring 編程的最佳入口

bcc/libbpf-tools- biolatency、biosnoop 等工具的 libbpf 版本源碼,比 Python 版性能更好

NVMe CLI- NVMe 設(shè)備管理和診斷的命令行工具集,支持 SMART 信息查看、固件更新、namespace 管理

Systems Performance, 2nd Edition (Brendan Gregg)- 系統(tǒng)性能分析的經(jīng)典著作,磁盤 IO 章節(jié)覆蓋了從原理到工具的完整知識(shí)體系

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    9

    文章

    3210

    瀏覽量

    76369
  • 磁盤
    +關(guān)注

    關(guān)注

    1

    文章

    398

    瀏覽量

    26474
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    4020

    瀏覽量

    68349

原文標(biāo)題:磁盤 IO 飆升導(dǎo)致系統(tǒng)卡死?iostat 與 iotop 深度實(shí)戰(zhàn)

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    HarmonyOS AI輔助編程工具(CodeGenie)智慧調(diào)優(yōu)

    DevEco Studio提供智慧調(diào)優(yōu)能力,支持通過自然語言交互,分析并解釋當(dāng)前實(shí)例或項(xiàng)目中存在的性能問題,幫助開發(fā)者快速定位影響性能的具體原因。該功能從DevEco Studio 6.0.0
    發(fā)表于 08-14 11:12

    HarmonyOSAI編程智慧調(diào)優(yōu)

    DevEco Studio提供智慧調(diào)優(yōu)能力,支持通過自然語言交互,分析并解釋當(dāng)前實(shí)例或項(xiàng)目中存在的性能問題,幫助開發(fā)者快速定位影響性能的具體原因。該功能從DevEco Studio 6.0.0
    發(fā)表于 09-01 15:15

    基于全HDD aarch64服務(wù)器的Ceph性能調(diào)優(yōu)實(shí)踐總結(jié)

    ,磁盤的性能得到了成倍的提升,如下圖。網(wǎng)絡(luò)帶寬也成倍增長。所以,我們可以基于不同的測(cè)試場(chǎng)景,不同的塊大小,去選擇升級(jí)磁盤和網(wǎng)絡(luò)設(shè)備來提升性能。當(dāng)然,TCO也是需要考慮的。4.2 Ceph軟件層面調(diào)
    發(fā)表于 07-05 14:26

    infosphere CDC性能調(diào)優(yōu)的文檔

    infosphere CDC性能調(diào)優(yōu)的文檔
    發(fā)表于 09-07 09:30 ?7次下載
    infosphere CDC性能<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>的文檔

    如何對(duì)電機(jī)進(jìn)行調(diào)優(yōu)調(diào)優(yōu)的好處是什么?

    如何自動(dòng)對(duì)電機(jī)進(jìn)行調(diào)優(yōu)
    的頭像 發(fā)表于 08-22 00:03 ?4022次閱讀

    Linux用電功耗調(diào)優(yōu)的筆記分享

    整理一些Linux用電功耗調(diào)優(yōu)的筆記,分享給小伙伴,關(guān)于用電調(diào)優(yōu)個(gè)人覺得
    的頭像 發(fā)表于 06-23 15:19 ?5579次閱讀

    關(guān)于JVM的調(diào)優(yōu)知識(shí)

    最近很多小伙伴跟我說,自己學(xué)了不少JVM的調(diào)優(yōu)知識(shí),但是在實(shí)際工作中卻不知道何時(shí)對(duì)JVM進(jìn)行調(diào)優(yōu)。今天,我就為大家介紹幾種JVM調(diào)
    的頭像 發(fā)表于 09-14 14:54 ?1404次閱讀

    KeenOpt調(diào)優(yōu)算法框架實(shí)現(xiàn)對(duì)調(diào)優(yōu)對(duì)象和配套工具的快速適配

    今天, KeenTune 再次帶來開源重磅特性——新增通用的調(diào)優(yōu)算法框架:keenopt。有了 keenopt 的加持,KeenTune 不再僅僅是支持靈活擴(kuò)展調(diào)優(yōu)場(chǎng)景的
    的頭像 發(fā)表于 11-11 09:31 ?1584次閱讀

    jvm調(diào)優(yōu)主要是調(diào)哪里

    JVM調(diào)優(yōu)主要涉及內(nèi)存管理、垃圾回收、線程管理與鎖優(yōu)化等方面。下面將詳細(xì)介紹每個(gè)方面的調(diào)優(yōu)技術(shù)和策略以及如何進(jìn)行優(yōu)化。 內(nèi)存管理 JVM的內(nèi)存管理主要包括堆內(nèi)存、棧內(nèi)存和非堆內(nèi)存。堆內(nèi)
    的頭像 發(fā)表于 12-05 11:37 ?2297次閱讀

    jvm調(diào)優(yōu)工具有哪些

    JVM調(diào)優(yōu)是提高Java應(yīng)用程序性能的重要手段,而JVM調(diào)優(yōu)工具則是輔助開發(fā)人員進(jìn)行調(diào)優(yōu)工作的利
    的頭像 發(fā)表于 12-05 11:44 ?1994次閱讀

    鴻蒙開發(fā)實(shí)戰(zhàn):【性能調(diào)優(yōu)組件】

    性能調(diào)優(yōu)組件包含系統(tǒng)和應(yīng)用調(diào)優(yōu)框架,旨在為開發(fā)者提供一套性能調(diào)優(yōu)平臺(tái),可以用來分析內(nèi)存、性能等問
    的頭像 發(fā)表于 03-13 15:12 ?1391次閱讀
    鴻蒙開發(fā)實(shí)戰(zhàn):【性能<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>組件】

    深度解析JVM調(diào)優(yōu)實(shí)踐應(yīng)用

    Tomcat自身的調(diào)優(yōu)是針對(duì)conf/server.xml中的幾個(gè)參數(shù)的調(diào)優(yōu)設(shè)置。首先是對(duì)這幾個(gè)參數(shù)的含義要有深刻而清楚的理解。
    的頭像 發(fā)表于 04-01 10:24 ?1329次閱讀
    深度解析JVM<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>實(shí)踐應(yīng)用

    Linux磁盤IO詳細(xì)解析

      在講解磁盤IO前,先簡單說下什么是磁盤。磁盤是可以持久化存儲(chǔ)的設(shè)備,根據(jù)存儲(chǔ)介質(zhì)的不同,常見磁盤可以分為兩類:機(jī)械
    的頭像 發(fā)表于 08-05 15:49 ?2629次閱讀
    Linux<b class='flag-5'>磁盤</b><b class='flag-5'>IO</b>詳細(xì)解析

    MMC SW調(diào)優(yōu)算法

    電子發(fā)燒友網(wǎng)站提供《MMC SW調(diào)優(yōu)算法.pdf》資料免費(fèi)下載
    發(fā)表于 09-20 11:14 ?0次下載
    MMC SW<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>算法

    MMC DLL調(diào)優(yōu)

    電子發(fā)燒友網(wǎng)站提供《MMC DLL調(diào)優(yōu).pdf》資料免費(fèi)下載
    發(fā)表于 10-11 11:48 ?0次下載
    MMC DLL<b class='flag-5'>調(diào)</b><b class='flag-5'>優(yōu)</b>