在Linux系統上,若是I/O發生性能問題,有沒有辦法進一步定位故障位置呢?iostat等最經常使用的工具確定是期望不上的,【容易被誤讀的iostat】一文中解釋過await表示單個I/O所需的平均時間,但它同時包含了I/O Scheduler所消耗的時間和硬件所消耗的時間,因此不能做爲硬件性能的指標,至於iostat的svctm更是一個廢棄的指標,手冊上已經明確說明了的。blktrace在這種場合就能派上用場,由於它能記錄I/O所經歷的各個步驟,從中能夠分析是IO Scheduler慢仍是硬件響應慢。linux
blktrace的原理ios
一個I/O請求進入block layer以後,可能會經歷下面的過程:網絡
blktrace能記錄I/O所經歷的各個步驟,來看一下它記錄的數據,包含9個字段,下圖標示了其中8個字段的含義,大體的意思是「哪一個進程在訪問哪一個硬盤的哪一個扇區,進行什麼操做,進行到哪一個步驟,時間戳是多少」:app
第7個字段在上圖中沒有標出來,它表示操做類型,具體含義是:」R」 for Read, 「W」 for Write, 「D」 for block, 「B」 for Barrier operation。異步
第6個字段是Event,表明了一個I/O請求所經歷的各個階段,具體含義在blkparse的手冊頁中有解釋,其中最重要的幾個階段以下:函數
Q – 即將生成IO請求 | G – IO請求生成 | I – IO請求進入IO Scheduler隊列 | D – IO請求進入driver | C – IO請求執行完畢
根據以上步驟對應的時間戳就能夠計算出I/O請求在每一個階段所消耗的時間:工具
Q2G – 生成IO請求所消耗的時間,包括remap和split的時間;
G2I – IO請求進入IO Scheduler所消耗的時間,包括merge的時間;
I2D – IO請求在IO Scheduler中等待的時間;
D2C – IO請求在driver和硬件上所消耗的時間;
Q2C – 整個IO請求所消耗的時間(Q2I + I2D + D2C = Q2C),至關於iostat的await。性能
若是I/O性能慢的話,以上指標有助於進一步定位緩慢發生的地方:
D2C能夠做爲硬件性能的指標;
I2D能夠做爲IO Scheduler性能的指標。spa
blktrace的用法debug
使用blktrace須要掛載debugfs:
$ mount -t debugfs debugfs /sys/kernel/debug
利用blktrace查看實時數據的方法,好比要看的硬盤是sdb:
$ blktrace -d /dev/sdb -o – | blkparse -i –
須要中止的時候,按Ctrl-C。
以上命令也能夠用下面的腳本代替:
$ btrace /dev/sdb
利用blktrace把數據記錄在文件裏,以供過後分析:
$ blktrace -d /dev/sdb
缺省的輸出文件名是 sdb.blktrace.<cpu>,每一個CPU對應一個文件。
你也能夠用-o參數指定本身的輸出文件名。
利用blkparse命令分析blktrace記錄的數據:
$ blkparse -i sdb
$ blktrace -d /dev/sdb $ blkparse -i sdb # 第一個IO開始: 8,16 1 1 0.000000000 18166 Q R 0 + 1 [dd] 8,16 1 0 0.000009827 0 m N cfq18166S /user.slice alloced 8,16 1 2 0.000010451 18166 G R 0 + 1 [dd] 8,16 1 3 0.000011056 18166 P N [dd] 8,16 1 4 0.000012255 18166 I R 0 + 1 [dd] 8,16 1 0 0.000013477 0 m N cfq18166S /user.slice insert_request 8,16 1 0 0.000014526 0 m N cfq18166S /user.slice add_to_rr 8,16 1 5 0.000016643 18166 U N [dd] 1 8,16 1 0 0.000017522 0 m N cfq workload slice:300 8,16 1 0 0.000018880 0 m N cfq18166S /user.slice set_active wl_class:0 wl_type:2 8,16 1 0 0.000020594 0 m N cfq18166S /user.slice fifo= (null) 8,16 1 0 0.000021462 0 m N cfq18166S /user.slice dispatch_insert 8,16 1 0 0.000022898 0 m N cfq18166S /user.slice dispatched a request 8,16 1 0 0.000023786 0 m N cfq18166S /user.slice activate rq, drv=1 8,16 1 6 0.000023977 18166 D R 0 + 1 [dd] 8,16 0 1 0.014270153 0 C R 0 + 1 [0] # 第一個IO結束。 8,16 0 0 0.014278115 0 m N cfq18166S /user.slice complete rqnoidle 0 8,16 0 0 0.014280044 0 m N cfq18166S /user.slice set_slice=100 8,16 0 0 0.014282217 0 m N cfq18166S /user.slice arm_idle: 8 group_idle: 0 8,16 0 0 0.014282728 0 m N cfq schedule dispatch # 第二個IO開始: 8,16 1 7 0.014298247 18166 Q R 1 + 1 [dd] 8,16 1 8 0.014300522 18166 G R 1 + 1 [dd] 8,16 1 9 0.014300984 18166 P N [dd] 8,16 1 10 0.014301996 18166 I R 1 + 1 [dd] 8,16 1 0 0.014303864 0 m N cfq18166S /user.slice insert_request 8,16 1 11 0.014304981 18166 U N [dd] 1 8,16 1 0 0.014306368 0 m N cfq18166S /user.slice dispatch_insert 8,16 1 0 0.014307793 0 m N cfq18166S /user.slice dispatched a request 8,16 1 0 0.014308763 0 m N cfq18166S /user.slice activate rq, drv=1 8,16 1 12 0.014308962 18166 D R 1 + 1 [dd] 8,16 0 2 0.014518615 0 C R 1 + 1 [0] # 第二個IO結束。 8,16 0 0 0.014523548 0 m N cfq18166S /user.slice complete rqnoidle 0 8,16 0 0 0.014525334 0 m N cfq18166S /user.slice arm_idle: 8 group_idle: 0 8,16 0 0 0.014525676 0 m N cfq schedule dispatch # 第三個IO開始: 8,16 1 13 0.014531022 18166 Q R 2 + 1 [dd] ...
利用btt分析blktrace數據
blkparse只是將blktrace數據轉成能夠人工閱讀的格式,因爲數據量一般很大,人工分析並不輕鬆。btt是對blktrace數據進行自動分析的工具。
btt不能分析實時數據,只能對blktrace保存的數據文件進行分析。使用方法:
把本來按CPU分別保存的文件合併成一個,合併後的文件名爲sdb.blktrace.bin:
$ blkparse -i sdb -d sdb.blktrace.bin
執行btt對sdb.blktrace.bin進行分析:
$ btt -i sdb.blktrace.bin
下面是一個btt實例:
... ALL MIN AVG MAX N --------------- ------------- ------------- ------------- ----------- Q2Q 0.000138923 0.000154010 0.014298247 94558 Q2G 0.000001154 0.000001661 0.000017313 94559 G2I 0.000000883 0.000001197 0.000012011 94559 I2D 0.000004722 0.000005761 0.000027286 94559 D2C 0.000118840 0.000129201 0.014246176 94558 Q2C 0.000125953 0.000137820 0.014270153 94558 ==================== Device Overhead ==================== DEV | Q2G G2I Q2M I2D D2C ---------- | --------- --------- --------- --------- --------- ( 8, 16) | 1.2050% 0.8688% 0.0000% 4.1801% 93.7461% ---------- | --------- --------- --------- --------- --------- Overall | 1.2050% 0.8688% 0.0000% 4.1801% 93.7461% ...
咱們看到93.7461%的時間消耗在D2C,也就是硬件層,這是正常的,咱們說過D2C是衡量硬件性能的指標,這裏單個IO平均0.129201毫秒,已是至關快了,單個IO最慢14.246176 毫秒,不算壞。Q2G和G2I都很小,徹底正常。I2D稍微有點大,應該是cfq scheduler的調度策略形成的,你能夠試試其它scheduler,好比deadline,比較二者的差別,而後選擇最適合你應用特色的那個 。