レベル: 初級 秋田 英行, 日本アイ・ビー・エム
2007年 4月 27日 過負荷状態となったとき、OSの内部ではどのような動作が行われているのでしょうか。ここでは、幾つかのツールを使用して、ステータスの解釈やデータ分析を行ってみましょう。問題を解決するには、まず問題を知れ、です。
前回、CPUおよびメモリに負荷をかけるツールを用い、OSの過負荷状態を作りだしました。そして、システムの構成情報および、その状態下での稼働情報を取得するまでを解説してきました。「状況把握」「情報収集」「データ分析」「解決を図る」というPDの手順のうち、情報収集までが終わった段階です。
今回は、こうしたデータを用いて、ステータスの解釈やデータ分析方法に足を踏み入れていきましょう。
ステップ3 データの解析
前回取得した3つのデータのうち、まずはvmstatの出力を見てみましょう。リスト1はvmstat.logの一部です。
リスト1 vmstatの出力例
拡大図
また、リスト中の空きメモリと割り当て済みスワップメモリ量、CPU使用状況の時間変化をグラフ化したものが図1になります。リスト1における各項目の意味は表1やmanページを参照してください。
図1 システム状況の変化
拡大図
表1. vmstatの出力項目
| 分類 | 項目 | 意味 |
|---|
| procs | r | 実行待ち状態のプロセス数 | | b | スリープ状態のプロセス数 | | memory | swpd | 総仮想メモリ量(Kバイト) | | free | 空きメモリ量(Kバイト) | | buff | バッファとして確保されているメモリ量(Kバイト) | | cache | キャッシュとして確保されているメモリ量(Kバイト) | | swap | si | ディスクからメモリにロードした(スワップイン)仮想メモリ量(Kバイト/秒) | | so | メモリからディスクに退避した(スワップアウト)仮想メモリ量(Kバイト/秒) | | io | bi | ブロックデバイスから受け取ったブロック数(ブロック/秒) | | bo | ブロックデバイスへ出力したブロック数(ブロック/秒) | | system | in | 1秒当たりの割り込み数 | | cs | 1秒当たりのコンテキストスイッチ数 | | cpu | us | ユーザープロセスで消費されたCPU時間 | | sy | カーネルで消費されたCPU時間 | | id | 待機状態で消費されたCPU時間 | | wa | I/O待ちのために消費されたCPU時間 |
※CD/DVDドライブでは1ブロック=2Kバイト、そのほかのデバイスでは1ブロック=1Kバイト
swaptestプログラムが消費するメモリ量は先に述べたとおり次のようになります。
1Mバイト×配列数10×プロセス数(引数の値+1)13=130Mバイト
|
一方、swaptestプログラムを実行することでfree領域は約135Mバイト減少しています。これはほぼ計算どおりです*。
さらに再度swaptestプログラムを実行すると、free領域は約90Mバイト減少し、同時に約35Mバイトのスワップアウト*が発生します。こちらも、おおむね計算どおりです。free領域が約3Mバイトほど残っているのは、カーネルは自身の実行用に最低限のメモリを確保しておくポリシーを持っているからです。
さて、2回目のswaptestプログラム実行後、vmstatの出力には次のような変化が見られます。まず、メモリを確保するためにスワップが頻繁に発生し、それに伴ってブロックI/Oも多発していることが分かるでしょう。
また、b、in、cs、waの増加にも注目してください。CPUがI/O待ち状態になっている時間を表すwaの値が増加しているにもかかわらず、CPUが実際に働いている時間を表すusとsyは合わせて40%程度しかありません。つまり、CPUの実行時間の60%がI/O待ちに使われており、効率的にCPUが使用されていないことになります。これを裏付けるのがin(割り込み回数)とcs(コンテキストスイッチ数)の増加です。これらはプロセスに割り当てられた実行時間を使いきり、ほかのプロセスに実行を渡すための割り込みが入った場合にカウントアップされます。つまり、I/O待ちのためにプロセスに割り当てられた実行時間を有効に使いきれない、という現象が発生しているのです。
また、bの値が増加していますが、この値は「I/O待ちなどでsleep状態になっており、割り込みを受け付けないプロセス数」を示しています。このような状態を「ブロック状態」と呼びます。vmstatの結果だけではどのプロセスがブロック状態となっているのかまでは分かりませんが、プロセス実行の際にI/Oが必要となり、I/O待ちのプロセスが多数発生して遅延が起こっている、ということになります。
今回実行しているプログラムはメモリアロケーションが主な処理であり、ファイルやディスクなどへの要求は行っていません。しかし、スワップが発生すれば当然スワップデバイスへのI/Oが発生し、このI/Oが円滑に行われなければ空きメモリ領域を作るためのスワップアウトや、再実行で必要なスワップインなどに影響が出てしまうため、ほかのプロセスにも影響が及んでしまうでしょう。
現に、このケースではスワップやI/Oに関連する項目の値が2回目のswaptestプログラム実行後大幅に増加し、このタイミングでコンソール操作やネットワークアクセスに影響が出ています。つまり、in、cs、bの増加はスワップのためのI/Oが大きな要因ではないかと推測できるのです。
では、次にI/Oそのものをiostatの出力結果(リスト2)から調べてみましょう。なお、リスト2の各項目の意味は表2のとおりです。また、図2はスワップデバイス(sda2)に対する1秒当たりの総書き込み/読み出しリクエスト数の時間変化を示したグラフになります。
リスト2 iostatの出力結果
拡大図
表2 iostatの出力項目
| 項目 | 説明 |
|---|
| %user | ユーザープロセスで消費されたCPU時間 | | %nice | 優先度が変更されているユーザープロセスで消費されたCPU時間 | | %sys | カーネルで消費されたCPU時間 | | %iowait | I/O待ちのために消費されたCPU時間 | | %idle | 待機状態で消費されたCPU時間 | | rrqm/s | デバイスに対する総読み出しリクエスト数 | | wrqm/s | デバイスに対する総書き込みリクエスト数 | | r/s | デバイスに対する読み出しリクエスト数 | | w/s | デバイスに対する書き込みリクエスト数 | | rsec/s | デバイスから読み出したセクタ数 | | wsec/s | デバイスに書き込んだセクタ数 | | rkB/s | デバイスから読み出したデータ量(Kバイト) | | wkB/s | デバイスに書き込んだデータ量(Kバイト) | | avgrq-sz | デバイスに対する平均転送量(セクタ数) | | avgqu-sz | デバイスに対する転送に使われたキューの平均サイズ | | await | デバイスに対するI/Oリクエストの平均待ち時間(ミリ秒) | | svctm | デバイスがI/Oリクエストを受けられる状態であった平均時間(ミリ秒) | | %util | デバイスに対するI/Oリクエストを処理するのに必要なCPU時間 |
図2 スワップデバイスsda2に対するリクエスト数の変化
拡大図
リスト2の一番上、「03時35分36秒」の時点ではまだswaptestプログラムは1回しか実行していません。データの出力先であるsda3に対しては若干のI/Oがあるものの、スワップデバイスであるsda2はまったく使用されていないことが分かります。
次の「03時35分37秒」はswaptestプログラムを2回目に実行した直後のデータです。ここではsda2に対するI/O、つまりスワップが起こり始めています。
さらに1秒後の「03時35分38秒」では、sda2へのI/Oが一気に増加し、その使用率も100%を超える数値になっています。以後、I/O待ち時間(%iowait)の値は70%を、I/Oに対するCPUの使用率(%util)の値も2本目のプログラムを終了させるまで80%を超え続けました。これらの結果から、明らかにスワップデバイスへのI/Oがパフォーマンスのボトルネックになっていることが分かるのです。
ステップ4 プロセスへの影響
発生した遅延の原因がスワップによるI/Oにある、と分かったところで、今度はこの事象が実際にはどのプロセスに大きく影響を与えていたか、topの出力データを使って確認してみましょう。なお、プロセスへの影響度を測るには各pid*ごとに総実行時間を算出すれば良いですが、これはtopの出力からは難しいため、先に述べたvmstatでbフィールドにカウントされているブロック状態のプロセスを特定してみましょう。なお、プロセスの総実行時間を得る場合、topを使用するのではなくtimeコマンドを利用するのが確実です。
図3は取得したtop実行結果の一部です。topの各項目の意味は表3やmanページを参照してください。
図3 topによるプロセス状態の取得
拡大図
表3 topの出力項目
| 項目 | 説明 |
|---|
| PID | プロセスID | | USER | プロセスの所有ユーザー | | PRI | プロセスの優先度 | | NI | プロセスのNICE値 | | SIZE | プロセスが使用している総メモリサイズ(Kバイト) | | RSS | プロセスが使用している物理メモリサイズ | | SHARE | プロセスが使用している共有メモリサイズ(Kバイト) | | STAT | プロセスの状態(S:スリープ状態、D:ブロック状態、R:実行中、W:スワップアウト状態など) | | %CPU | プロセスのCPU使用率 | | %MEM | プロセスの物理メモリ使用率 | | TIME | プロセスが使用した総CPU時間 | | CPU | プロセスが使用したCPU | | COMMAND | プロセスの起動コマンド |
topの出力からブロックされているプロセスを特定するには、STATフィールドのプロセス状態を示すステータスが「D」となっているプロセスを探します。図3では幾つかのswaptestプロセスがブロックされていることが分かるでしょう。
今回のケースではスワップがボトルネックになっているわけですが、これと結びつけられるデータがもう1つ確認できます。STATがDとなっているswaptestと、Sとなっているswaptestでは、RSS、つまり使用している物理メモリサイズが大きく異なっている点です。
swaptestプログラム自体は各子プロセス当たり10Mバイトのメモリアロケーションを行います。一方、STATがSとなっているswaptestのRSSはプログラムどおりの10Mバイトですが、DとなっているswaptestのRSSは10Mバイトに満たないのです。
これらから、次のような現象が発生しているということが分かります。
- swaptestが10Mバイトのメモリアロケーション要求をする
- 物理メモリが不足しているため、メモリアロケータはスワップによって空きスペースを作ろうとI/Oを発生させる
- I/O待ちのため、プロセスはブロック状態となる
このとき、STATがDとなったプロセスはI/Oが終了し、メモリが利用できるようになるまで実行再開ができないため遅延が発生するのです。
ステップ5 ボトルネックの解消
スワップに関するボトルネックの解消には、以下の3つの方法が効果的です。
- スワップデバイスの分散
- メモリの追加
- プロセス単位のメモリ使用量削減
Linuxにおけるスワップ処理は、主にカーネルプロセスのkswapdが行うのですが、しばしば性能面でのパフォーマンス劣化が取りざたされます。カーネル2.6になってページ参照のアルゴリズムは大幅に進歩し、その効果も上がってはいるものの、スワップ周りの性能を構成面、設計面で配慮するに越したことはありません。
1の「スワップデバイスの分散」は、単にパーティーションやディスクを分割するのではなく、デバイスのコントローラーやチャネルを分割するほか、バスの帯域やコントローラーキャッシュを分散することで物理ディスクへのI/O性能を考慮することを示唆しています。
2の「メモリの追加」は、物理メモリ領域の枯渇状態を軽減し、スワップそのものを減少させることを目的としています。
3の「プロセス単位のメモリ使用量削減」は、必要なデータセグメント*を最小限にするプログラム設計や起動プロセスの削減、子プロセスのスレッド化などが該当します。
今回のまとめ
2回にわたってシステムに負荷をかけた状態で発生する遅延、というトラブルケースをシミュレーションし、実際にツールを使ってPDを行う例を紹介しました。また、ツールの使用方法だけでなく、ステータスの解釈やデータ分析方法にも足を踏み入れています。もちろん、今回の例が問題のすべてではないですし、実際に発生するさまざまなケースでは、その状況によって解釈や分析結果も変わってきます。そのため、トラブルを実際に作らなくとも日々のオペレーションやベンチマーク時などにリソース情報を収集し、カーネルの挙動を理解することをお勧めします。
このページで出てきた専門用語
-
ほぼ計算どおりです
- 誤差は、ページヘッダーやスタックなど。
-
スワップアウト
- 物理メモリ内に記録した情報をスワップデバイスに退避すること。逆にスワップデバイスに退避していた情報を物理メモりに戻すことをスワップインと呼びます。
-
pid
- Process ID。各プロセスが固有に持つID。
-
データセグメント
- プログラム中で使用するデータが格納されるメモリ領域のこと。
参考文献
著者について  | |  | 秋田英行(日本アイ・ビー・エム) |
記事の評価
|