利用blktrace分析IO性能

本文轉載自一位專家朋友(微博@vmunix)的博客,他從事UNIX性能方面的工作近十年,今年來開始研究Linux。原文地址:http://linuxperf.com/?p=161

iostat等最常用的工具肯定是指望不上的,【容易被誤讀的iostat】一文中解釋過await表示單個I/O所需的平均時間,但它同時包含了I/O Scheduler所消耗的時間和硬件所消耗的時間,所以不能作爲硬件性能的指標,至於iostat的svctm更是一個廢棄的指標,手冊上已經明確說明了的。blktrace在這種場合就能派上用場,因爲它能記錄I/O所經歷的各個步驟,從中可以分析是IO Scheduler慢還是硬件響應慢。


blktrace的原理


一個I/O請求進入block layer之後,可能會經歷下面的過程:


  • Remap: 可能被DM(Device Mapper)或MD(Multiple Device, Software RAID) remap到其它設備

  • Split: 可能會因爲I/O請求與扇區邊界未對齊、或者size太大而被分拆(split)成多個物理I/O

  • Merge: 可能會因爲與其它I/O請求的物理位置相鄰而合併(merge)成一個I/O

  • 被IO Scheduler依照調度策略發送給driver

  • 被driver提交給硬件,經過HBA、電纜(光纖、網線等)、交換機(SAN或網絡)、最後到達存儲設備,設備完成IO請求之後再把結果發回。


blktrace能記錄I/O所經歷的各個步驟,來看一下它記錄的數據,包含9個字段,下圖標示了其中8個字段的含義,大致的意思是“哪個進程在訪問哪個硬盤的哪個扇區,進行什麼操作,進行到哪個步驟,時間戳是多少”:



第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性能的指標。


blktrace的用法


使用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對應一個文件。
你也可以用-o參數指定自己的輸出文件名。


利用blkparse命令分析blktrace記錄的數據:
$ blkparse -i sdb



注:
在以上數據中,有一些記錄的event類型是”m”,那是IO Scheduler的調度信息,對研究IO Scheduler問題有意義:


  • cfq18166S – cfq是IO Scheduler的名稱,18166是進程號,”S”表示Sync(同步IO),如果異步IO則用“A”表示(Async);

  • 它們的第三列sequence number都是0;

  • 它們表示IO Scheduler內部的關鍵函數,上例中是cfq,代碼參見block/cfq-iosched.c,以下是各關鍵字所對應的內部函數:
    alloced <<< cfq_find_alloc_queue()
    insert_request <<< cfq_insert_request()
    add_to_rr <<< cfq_add_cfqq_rr()
    cfq workload slice:300 <<< choose_wl_class_and_type()
    set_active wl_class:0 wl_type:2 <<< __cfq_set_active_queue()
    fifo= (null) <<< cfq_check_fifo()
    dispatch_insert <<< cfq_dispatch_insert()
    dispatched a request <<< cfq_dispatch_requests()
    activate rq, drv=1 <<< cfq_activate_request()
    complete rqnoidle 0 <<< cfq_completed_request()
    set_slice=100 <<< cfq_set_prio_slice()
    arm_idle: 8 group_idle: 0 <<< cfq_arm_slice_timer()
    cfq schedule dispatch <<< cfq_schedule_dispatch()


利用btt分析blktrace數據


blkparse只是將blktrace數據轉成可以人工閱讀的格式,由於數據量通常很大,人工分析並不輕鬆。btt是對blktrace數據進行自動分析的工具。


btt不能分析實時數據,只能對blktrace保存的數據文件進行分析。使用方法:

把原本按CPU分別保存的文件合併成一個,文件名爲sdb.bin:
$ blkparse -i sdb -d sdb.blktrace.bin
$ btt -i sdb.blktrace.bin


下面是一個btt實例:



我們看到93.7461%的時間消耗在D2C,也就是硬件層,這是正常的,我們說過D2C是衡量硬件性能的指標,這裏單個IO平均0.129201毫秒,已經是相當快了,單個IO最慢14.246176 毫秒,不算壞。Q2G和G2I都很小,完全正常。I2D稍微有點大,應該是cfq scheduler的調度策略造成的,你可以試試其它scheduler,比如deadline,比較兩者的差異,然後選擇最適合你應用特點的那個。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章