Y-110's Wiki
サーバ診断:vmstat
_ vmstat によるサーバ診断
vmstat はサーバのプロセス, メモリ, スワップ, I/O, CPU 等を確認できるコマンドで, サーバの状態を知るのには欠かせないツールです。
実際の vmstat の出力は以下のようになります。
$ vmstat 2 procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 1 0 4268 21500 161164 546304 0 0 3 2 3 3 32 3 65 0 6 0 4268 22204 161164 546304 0 0 2 108 0 624 80 6 14 0 6 1 4268 21180 161164 546372 0 0 1 326 0 616 82 7 11 0 9 0 4268 17424 161172 546364 0 0 7 256 0 827 79 9 12 0
一番最初の行は, 前回起動時からの平均値で, 2行目以降は実行した時点での状態を表示しています。
上の例では2秒毎に vmstat を実行して結果を表示しています。
単に vmstat と実行しただけでは平均値しか得られないので, 今のサーバの状態を知りたい場合は必ずインターバルを指定してください。
以下, サーバ診断をする際に重要な項目を簡単に説明します。
プロセス r: 実行待ちプロセス数 b: 割り込み不可プロセス数(多くの場合 I/O 待ちプロセス) メモリ swpd: スワップ使用量 free: 空きメモリ量 スワップ si: ディスクからのメモリスワップ量 so: ディスクへのメモリスワップ量 I/O bi: ブロックデバイスからの読込みブロック数 bo: ブロックデバイスへの書込みブロック数 CPU us: ユーザCPU利用率 sy: システムCPU利用率 id: CPUアイドル率 wa: IO待ちCPU利用率
_ 傾向と対策
サーバに負荷がかかる原因は様々ですが, vmstat で診断できる典型的なパターンとその対策を紹介します。
_ r のプロセスが多く us の CPU利用率が高い
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 3 0 4264 46056 158060 536052 0 0 3 2 3 3 32 3 65 0 6 0 4264 43720 158068 536044 0 0 2 138 0 658 79 10 12 0 11 0 4264 41032 158068 536044 0 0 1 531 0 594 71 7 22 1
r のプロセス数が CPU の数より大きい場合, 実行可能プロセスが CPU 待ちをしている状態にあります。
また us の CPU利用率も高く, これはアプリケーションの処理に CPU が使われていることを表しています。
CPU はアプリケーションの処理にフル稼働しているのですが, タスクが多すぎて捌ききれていない状態です。
銀行の窓口に例えると, 銀行員は一生懸命働いているのですが, お客さんがたくさんいて処理が追いつかず, 行列ができているようなものです。
このようなケースでは, 以下の対策があります。
- CPU のクロック数を上げる
- CPU の数を増やす
- アプリケーションをチューニングする
- サーバをスケールアウトする
まずは, アプリケーションで重い処理をやっていないかどうかを調査して CPU負荷の改善を計ります。
アプリケーションだけの対応では厳しい場合は, 物理的な対策を行いましょう。
_ si, so が多発している
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 3 4 334264 6056 158060 536052 789 1234 1234 762 1512 1723 53 7 10 30 1 10 337264 3720 158068 536044 607 800 782 1234 1485 2658 47 10 0 43 3 8 344264 1032 158068 536044 543 876 2231 2531 1871 1322 43 7 0 50
si, so を繰り返している場合は完全にメモリ不足の状態です。
この場合は, スラッシング状態に陥ってディスクからの読み書きも多くなり bi, bo がつられて大きくなる場合もあります。
また, swpd の値もどんどん大きくなっていき, 最悪の場合, サーバそのものがまともに応答を返さなくなります。
このようなケースでは, メモリの追加が一番手っ取り早いですが, アプリケーションでメモリを無駄に使っている所があればそこを改善しましょう。
基本的にスワップしたら負けです。
スワップしないように, 事前に十分なメモリを積んでおきましょう。
_ データベースサーバのスワップ
経験上, データベースサーバはメモリ不足によるスワップを起こしやすいです。
- 大量のデータを参照する SQL
- 永続的接続の接続数オーバー
SQL改善や永続的接続の接続数を制限する等, スワップしないように対策を行いましょう。
場合によっては一時的に永続的接続をやめて, メモリを増加してから元に戻すのも手です。
案件の規模にもよりますが, PostgreSQL や MySQL なら 4G のメモリを積んでおけばまず安心です。
PostgreSQL の事例ですが, メモリ 2G max_connection 512 で pconnect運用していて, 接続を使い切ってスワップ地獄に陥った経験があります。
その後メモリを 4G まで増設して, スワップは抑えることができました。
_ b のプロセスが多く, wa の CPU利用率が高い
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 0 10 22108 29964 38904 2762380 7 7 14 5 7 5 13 7 0 80 0 15 22108 27596 38912 2762984 71 20 856 1173 1623 3143 11 4 0 85 0 20 22108 24268 38920 2765084 30 12 1046 2188 1707 3193 12 10 0 78
b のプロセスが多いということは, I/O待ちをしているプロセスがたくさんあるということです。
I/O待ちプロセスが多くなる原因は色々ありますが, wa の CPU利用率が高く*1 bi/bo の値が大きければ, ハードディスクの読み書きが頻発している状態です。
このようなケースでは, 以下の対策があります。
- I/O性能を上げる
- SCSIディスクにする
- ハードディスクの回転数を上げる
- RAID の導入を検討する
- メモリディスク*2を利用する
- I/O負荷の原因となる処理を他サーバに切り離す
- 大きな負荷のかかるバッチ処理等
b のプロセスがあまりにも多く, CPU利用率や bi/bo の数値が低い場合は, サーバに何か異変が起こっている場合が多いです。
この場合は, 原因となっているプロセスを top や ps コマンドで特定し, プロセスを kill しましょう。
必要であれば strace*3 コマンドで, 当該プロセスがどのようなシステムコールが呼んでいるのかを確認して, より詳細な原因を調査します。
_ データベースサーバの割り込み不可プロセス
データベースのあるテーブルに更新処理が集中して, ロック解放待ちプロセスが溜まっていくと b のプロセスが増えていく傾向にあります。
この状態になると, サーバそのものは軽いものの, データベースが応答を返さなくなってしまいます。
過去に, PostgreSQL 7.4.x で外部参照制約(Foreign Key)を定義したテーブルに対して更新処理が短時間に多数走った際, ロックがどんどん溜まり b のプロセスが増え続け, データベースの再起動を余儀なくされたことがあります。
PostgreSQL の外部参照制約は, 内部ではトリガを使用しているため, 更新処理が走る毎にトリガがロックを獲得しに行き, アクセス増に伴いついに閾値を超えてロックがたまり続けるといった状態でした。
テーブルの外部参照制約をはずしたところ, この現象は改善されました。
PostgreSQL での外部参照制約はかなり重い処理になるので, 本番運用の際は制約をはずして運用すると負荷の軽減になります。
_ sy の CPU利用率が高い
procs memory page disk faults cpu r b w avm fre flt re pi po fr sr ad0 in sy cs us sy id 1 5 0 284684 52336 62 0 0 0 62 1 0 1260 319 336 7 30 63 0 10 0 284684 52336 1 0 0 0 1 0 0 1282 72 328 8 70 22 0 8 0 284684 52332 1 0 0 0 0 0 0 1275 76 318 6 85 9 (FreeBSD での vmstat の表示形式なので, Linux とは多少異なります)
これはちょっと限られた事例ですが, sy の CPU利用率が高く b のプロセスも多いケースがありました。
PHP でのセッションファイル共有のための NFSサーバで起こっていたのですが, アクセスが多い時間帯に sy の CPU利用率が高くなり若干重くなっていました。
原因は, 各 Webサーバでのセッションガベージコレクションが走る度に NFSサーバで readdir(2) が呼ばれ, 巨大なディレクトリツリーが転送されていたためでした。
ライフタイムを長めに取っていたこととユーザの増加のせいで, セッションファイルの数が 20〜30万と多くなりすぎていて, これらの情報を取得するのにカーネルコード部分で負荷がかかっていたようです。
sy の数値が高かったのは, readdir(2) のシステムコールで CPU時間が取られていたためでしょう。
wa がサポートされている vmstat では, wa の数値も高くなるかもしれません。
対策として, 各 Webサーバの php.ini を session.gc_probability = 0 に変更し, Webサーバ上でガベージコレクションが発生しないようにして, NFSサーバにて cron処理でセッションファイルを削除するようにしました。*4
PHP で複数の Webサーバでセッションを共有する場合, NFSサーバを立ててセッションファイルを共有する方法を取ることも多いかと思いますが*5, Webサーバからのガベージコレクションを行う場合は, 毎回ディレクトリツリー情報の通信が行われることを心に留めておいてください。
セッションファイルは割と頻繁にアクセスされるため, NFSサーバのパフォーマンスを上げるには, noatime オプションをつけて NFSマウントし, ファイルアクセス時刻を更新しないようにするのも有効です。
kernel 2.6 より前の vmstat では wa の項目がないので, sy の CPU利用率が高くなります
Linux だと tmpfsファイルシステム
FreeBSD では ktrace, Solaris なら truss
例えばこんなの。 */8 * * * * root /usr/bin/find /home/exports/tmp -type f -name "sess_*" -mmin +120 -exec rm \{\} \;
MCache (以前は msession)というセッションサーバを立てたり, データベースでセッションを共有する方法もあります