Y-110's Wiki


サーバ診断:vmstat

このページをdel.icio.usに追加 このページをはてなブックマークに追加このページを含むはてなブックマーク このページをlivedoor クリップに追加このページを含むlivedoor クリップ このページをYahoo!ブックマークに追加このページを含むYahoo!ブックマーク

_ 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 の数値が低い場合は, サーバに何か異変が起こっている場合が多いです。
この場合は, 原因となっているプロセスを topps コマンドで特定し, プロセスを 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)というセッションサーバを立てたり, データベースでセッションを共有する方法もあります


 
Link: 負荷対策概論(1285d) FrontPage(1373d)
Last-modified: 2006-05-24 (水) 18:07:59 (1528d)