やっぱり Sun がスキ! : Weblog やっぱり Sun がスキ!

やっぱり Sun がスキ!

http://blogs.sun.com/yappri/date/20090525 2009年 5月 25日 月曜日

iostat コマンドの読み方

はじめに

今回は iostat コマンドをご紹介したいと思います。iostat は I/O の統計情報を出力するコマンドです。物理ディスクやテープドライブ、ネットワーク越しにマウントしたファイルシステム、端末入出力等の入出力性能を監視する事が出来ます。I/O を監視するツールは他にも fsstat, nfsstat, zpool iostat, DTrace io Probider, kstat -p 'unix:0:biostats' 等がありますが、その中でも iostat は最も基本的で重要なコマンドです。是非ご活用下さい。

iostat のお勧めのオプション

-xnC 1

基本的なオプションとして -x, -n, -C オプションは常時付ける事をお勧めします。

 % iostat -xnC 1

x オプションは拡張表示を有効にするオプションです。iostat のデフォルトでは iostat が抜き出した幾つかのデバイスに付いて kps, tps, serv の 3 つの統計を表示するだけです。-x を付けると全てのデバイスが出力対象となり、出力される統計情報も増加します。I/O の解析を行う際は必須のオプションです。

n オプションはデバイス名を分かりやすく表示するオプションです。デフォルトではデバイス名は "ssd223" の様にドライバー名とインスタンス番号で表示されますが、-n オプションを付けると "c0t0d0" の様にディスクを特定しやすい名前で出力されます。これも必須のオプションと言って良いでしょう。常に付ける様にして下さい。

C オプションはコントローラ毎の統計情報も表示するオプションです。複数の HBA を使用しているシステムでは、コントローラをまたいで I/O 負荷を分散した方がスループットが上がります。個別のディスクの統計情報だけでなく、途中の経路における統計情報も取得する事で、より詳細な分析が可能になります。

1 はインターバルです。1 秒ごとに統計情報を表示します。iostat 実行の負荷は小さく、ログのサイズも今時のハードディスクのサイズを考えれば非常に小さいので、長期間の負荷を監視する場合でもより精度の高い情報を取得する為に 1 秒毎に出力する事をお勧めします。

その他のオプション

場合によっては -M や -z, -p, -m オプションを付けると便利です。

M オプションは "kr/s", "kw/s" を MB 表示に直します。内蔵ディスクでも数百 MB/s のスループットが出る時代ですし、FC の帯域はギガの単位ですので -M を付けた方が見易い場合も多くあります。ただし、細かい I/O が少量発生しているのを監視したい場合はデフォルトの KB 単位の方が良いかもしれません。

z オプションは出力結果の全ての性能値が 0 であった場合に表示を省略するオプションです。ディスクが沢山あって出力が画面をはみ出してしまう場合に便利です。毎回出力される行数が変わるのでログを取得する用途には向いていません。

p オプションはパーティション毎の統計情報も表示します。cXtXdXsX の sX 単位で出力されますので、どのスライスに I/O が発生しているかを見たい場合に使用して下さい。

m オプションは -n, -p と一緒に使用するとマウントポイントも表示します。どのデバイスに I/O が発生しているかが更に分かりやすくなります。

iostat の出力例

例1

 # iostat -xnC 1
 ...
                     extended device statistics
     r/s    w/s   kr/s   kw/s wait actv wsvc_t asvc_t  %w  %b device
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t6d0
     0.0   14.1    0.3  148.8  0.0  0.1    0.9    5.9   0   3 c1
     0.0    3.3    0.0   36.4  0.0  0.0    0.6    3.9   0   1 c1t1d0
     0.0    3.3    0.0   36.6  0.0  0.0    0.6    4.1   0   1 c1t4d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t13d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t8d0
     0.0    3.3    0.0   36.6  0.0  0.0    0.6    4.2   0   1 c1t3d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.5   0   0 c1t5d0
     0.0    0.8    0.3    2.8  0.0  0.0    5.7   34.0   0   0 c1t0d0
     0.0    3.3    0.0   36.4  0.0  0.0    0.6    4.2   0   1 c1t2d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 mikawa01.jp.iforce.net:vold(pid576)

例2

 # iostat -xnCmp 1
 ...
                     extended device statistics
     r/s    w/s   kr/s   kw/s wait actv wsvc_t asvc_t  %w  %b device
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c0t6d0
     0.0   14.1    0.3  148.8  0.0  0.1    0.9    5.9   0   3 c1
     0.0    3.3    0.0   36.4  0.0  0.0    0.6    3.9   0   1 c1t1d0
     0.0    3.3    0.0   36.4  0.0  0.0    0.6    3.9   0   1 c1t1d0s0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t1d0s2
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t1d0s3
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    1.0   0   0 c1t1d0s4
     0.0    3.3    0.0   36.6  0.0  0.0    0.6    4.1   0   1 c1t4d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t4d0s2
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.7   0   0 c1t4d0s3
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t4d0s4 
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t13d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t13d0s0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t13d0s1
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t13d0s2
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t8d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t8d0s2
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t8d0s3
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 c1t8d0s4
     0.0    3.3    0.0   36.6  0.0  0.0    0.6    4.2   0   1 c1t3d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.6   0   0 c1t3d0s1
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t3d0s2
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    1.3   0   0 c1t3d0s5
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.5   0   0 c1t5d0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.7   0   0 c1t5d0s2
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.7   0   0 c1t5d0s3 
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t5d0s4
     0.0    0.8    0.3    2.8  0.0  0.0    5.7   34.0   0   0 c1t0d0
     0.0    0.8    0.3    2.8  0.0  0.0    5.7   34.0   0   0 c1t0d0s0 (/)
     0.0    0.0    0.0    0.0  0.0  0.0    0.0   19.2   0   0 c1t0d0s1
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t0d0s2
     0.0    3.3    0.0   36.4  0.0  0.0    0.6    4.2   0   1 c1t2d0
     0.0    3.3    0.0   36.4  0.0  0.0    0.6    4.2   0   1 c1t2d0s0
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.8   0   0 c1t2d0s2
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    1.2   0   0 c1t2d0s6
     0.0    0.0    0.0    0.0  0.0  0.0    0.0    0.0   0   0 mikawa01.jp.iforce.net:vold(pid576)

各カラムの意味

r/s(りーどぱーせかんど)

r/s は毎秒何回読み出しを行っているかを表しています。r/s と w/s を足し合わせた値が IOPS になります。なお、iostat の間隔を何秒に設定しても 1 秒辺りの数値で出力されます。

r/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::reads' 等で iostat の r/s と近い出力を得る事が可能です。iostat コマンドの中ではデバイスパスを比較してデバイスを選り分けている様です。

該当する kstat の値は主に以下の場所で更新されています。

w/s(らいとぱーせかんど)

w/s は毎秒何回書き込みを行っているかを表しています。細かい I/O が発生して書き込み回数が増えると、帯域が余っていてもディスクコントローラがボトルネックになる事があります。

w/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::writes' 等で iostat の w/s と近い出力を得る事が可能です。

該当する kstat の値は主に以下の場所で更新されています。

kr/s(きろりーどぱーせかんど)

kr/s は毎秒何 KB 読み出しを行っているかを表しています。r/s と w/s が IOPS を表していたのに対し、こちらは I/O のスループットを表しています。

kr/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::nread' 等で iostat の kr/s と近い出力を得る事が可能です。

該当する kstat の値は主に以下の場所で更新されています。

kw/s(きろらいとばーせかんど)

kw/s は毎秒何 KB 書き込みを行っているかを表しています。

kw/s の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::nwritten' 等で iostat の kw/s と近い出力を得る事が可能です。

該当する kstat の値は主に以下の場所で更新されています。

wait(うぇいと)

wait は I/O 要求が受け付けられたものの、実行まで待たされている I/O の数を表しています。実行待ちしている I/O 要求の数は kstat wait queue という名前で管理されています。

wait の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::wlentime' 等で iostat の wait と近い出力を得る事が可能です。

該当する kstat の値はカーネル内の kstat_waitq_enter(), kstat_waitq_exit(), kstat_waitq_to_runq() ,kstat_runq_back_to_waitq() で更新されています。

  • sun4u システムでは /usr/src/uts/sun4u/cpu/common_asm.s の stx %o5, [%o0 + QTYPE/**/LENTIME]; が更新ポイントです。KSTAT_Q_UPDATE() マクロの QTYPE 引数が KSTAT_IO_W だった時に KSTAT_IO_WLENTIME として評価されます。更に KSTAT_IO_WLENTIME は /usr/src/uts/sun4/ml/offsets.in 内の定義によって wlentime に変換されます(offsets.in は common_asm.s でインクルードされている assym.h の元ファイルです)。
  • sun4v では /usr/src/uts/sun4v/cpu/common_asm.s の stx %o5, [%o0 + QTYPE/**/LENTIME]; で更新されています。
  • x86 では /usr/src/uts/common/os/kstat_fr.c の kiop->wlentime += kiop->wcnt * wfix; と kiop->wlentime += delta * wcnt; で更新されています。

actv(あくてぃぶ)

actv は毎秒、デバイスによって処理されている I/O 要求の数を表しています。現在処理されている I/O の数は kstat run queue という名前で管理されています。

actv の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::rlentime' 等で iostat の actv と近い出力を得る事が可能です。

kstat の rlentime の値はカーネル内の kstat_runq_enter(), kstat_runq_exit(), kstat_waitq_to_runq(), kstat_runq_back_to_waitq() で更新されています。具体的には以下の場所です。

wsvc_t(うぇいとさーびすたいむ)

wsvc_t は I/O 要求が待機させられている時間の平均値をミリ秒単位で表しています。待機待ちの I/O 要求の個数(wait) を IOPS(r/s と w/s を足した値) で割った値です。

wsvc_t の値は ("wait" / ("r/s" + "w/s") * 1000) の計算式で求められます。

asvc_t(あくてぃぶさーびすたいむ)

asvc_t は I/O 要求の処理に掛かった時間の平均値をミリ秒単位で表しています。処理中の I/O 要求の個数(actv) を IOPS(r/s と w/s を足した値) で割った値です。

asvc_t の値は ("actv" / ("r/s" + "w/s") * 1000) の計算式で求められます。

%w(ぱーせんとうぇいと)

%w は待機させられている I/O 要求が存在している時間の割合です。/usr/src/uts/common/sys/kstat.h に図示されている様に、この値は I/O 要求の数と時間のリーマン和になっています。

%w の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::wtime' 等で iostat の %w と近い出力を得る事が可能です。

kstat の wrime の値はカーネル内の kstat_waitq_enter(), kstat_waitq_exit(), kstat_waitq_to_runq(), kstat_runq_back_to_waitq() で更新されています。具体的には以下の場所です。

%b(ぱーせんとびじー)

%b はディスクが busy 状態になっている時間の割合です。%w と同じ様にリーマン和になっています。

%b の値はカーネル内の kstat データから I/O デバイスの読み出し回数を取得しています。kstat コマンドでも kstat -p '/md|nfs|fd|st|dad|sd|ssd|lofi|ramdisk/:::rtime' 等で iostat の %r と近い出力を得る事が可能です。

kstat の rtime の値はカーネル内の kstat_runq_enter(), kstat_runq_exit(), kstat_waitq_to_runq(), kstat_runq_back_to_waitq() で更新されています。具体的には以下の場所です。

device(でばいす)

device はデバイス名です。

値の見方

iostat コマンドの初回の出力はデバイスがオンラインになってから現在までの累積値です。2 回目からの出力がリアルタイムの値ですので、注意して下さい。

まずは %w と %b がどれだけ出ているかを確認します。通常は %b が 100% に達してから %w が発生します。%w が出ている時は I/O リクエストを完全には捌けておらず、I/O ボトルネックになっている状態です。%w が出ておらず、%b も 100% までいっていない場合は I/O に余力がある状態です。この状態では I/O ボトルネックを心配する必要はありません。

基本的な情報として IOPS と I/O サイズ、I/O スループットの 3 つを把握して下さい。IOPS は毎秒幾つの I/O リクエストを捌けているかという情報です。IOPS は "r/s" + "w/s" で求める事が出来ます。IOPS が多い場合は I/O リクエストが多量に発生しており、負荷が高くなっている状態です。

I/O サイズは "kr/s" / "r/s" が平均読み出しサイズ、 "kw/s" / "w/s" が平均書き込みサイズです。平均 I/O サイズが小さい場合は細かい書き込みが発生しており、一般的に性能が出にくい状態です。ある特定のプロセスがどんなサイズの I/O リクエストを出しているかは DTrace や truss で確認する事が出来ます。以下の様に truss を実行すると、入出力先のデバイス、I/O のサイズ、読み書きされているデータの中身、I/O に掛かった時間等、詳細な情報を入手する事が出来ます。

 % truss -E -vall -wall -rall -p 

I/O スループットは "kr/s" と "kw/s" のカラムを見ます。"kr/s" が毎秒何 KB 読み出しているか、"kw/s" が何 KB 書き込んでいるかを示しています。スループットの値は I/O パターンやディスクのレイアウトにも依りますが、期待したスループットが達成されているか確認して下さい。

I/O の重要な調査ポイントとして、発行されている I/O の特性も見極める必要があります。read only なのか write intensive なのか read と write の混在なのか、sequential access か random access か、等の I/O 特性によって I/O の性能は変化します。これらの情報は RAID 構成を決定する際のヒントにもなります。"r/s" が増加していて "w/s" が 0 の場合は read only access で、逆の場合は write only access です。I/O 特性が read only でデータサイズがそれ程大きくない場合は tmpfs にデータを置くと性能が大きく改善します。sequential か random かを iostat で正確に切り分ける方法はありませんが、read / write が両方発生している場合や、I/O サイズが不規則に変化している場合は random access の可能性が高いです。

関連するソースファイル

iostat の出力は iostat.c の show_disk() 関数にまとめられています。kstat からのデータの取得は acquire_iodevs.c の中で行っています。

参考文献

終わりに

以上、iostat の実装と読み方に付いて解説しました。IOPS、I/O サイズ、スループット、wait queue, run queue 等の情報を活用する事でサーバを健全な状態で運用する事が可能になります。vmstatmpstat 等のツールとともに頻繁に使用するツールですので、是非使い方を憶えて有効活用して下さい。