注意

この文書は2007/8/24に書かれたもので、ソフトウエアの名称、バージョン、設定項目、社名などの固有名詞などなどは当時のまま掲載しています。

ですので、インストール手順や設定内容は最新版のドキュメントを参照していただき、この文書からは理論や考え方、構成のヒントなどを読み取っていただければと思います。

はじめに

今回は、スケーラブルなシステムそのものではなく、「監視」にまつわる話を書きたいと思います。

前半は監視について概観し、後半では実際に使っている監視のしかけをいくつか紹介したいと思います。

なぜ監視をするか?

監視の詳細に入る前に、まずは「監視」という行為についてちょっと整理しておきましょう。

監視の目的

監視の目的は大きく分けると2つあると思います。

  1. 異常を検知する
  2. 変動を観察する

異常を検知する

まず、「異常を検知する」ですが、これはみなさんが「監視」にもっているイメージそのままなのではないでしょうか。具体例を挙げると、

  • サーバが止まった
  • HTTPアクセスできなくなった
  • ロードアベレージが10を越えた

といったものが「異常を検知する」にあてはまります。

システムを運用するにあたり、「正常」な状態を保ち続けるのがその目的のひとつとなります。したがって、「正常」ではない「異常」な状態を検知することが必要となってくるわけです。見方を変えると、「異常を検知する」監視は、障害対応を開始するきっかけと考えることもできます。

変動を観察する

次に「変動を観察する」です。具体的には、

  • サーバリソース(CPUやメモリの使用率)
  • ロードアベレージ
  • ネットワークトラフィック

といった値を継続的に記録し、視覚化し、傾向や変動をつかみやすくすることを意味します。

即座の対応が必要な「異常を検知する」とは違い「変動を観察する」は派手さはありませんが、実践しておくと後々、そのありがたさが感じられると思います。

例えば、メルマガやテレビコマーシャルや大手ポータルサイトへの広告掲載などといった、訴求活動をした場合、その瞬間に大量のアクセスが押し寄せてきます。アクセスが落ち着くまではあれやこれやの対応でいっぱいいっぱいなのですが、一段落してじゃぁどこがボトルネックになっていたのか?というときに、様々な情報の変動がグラフで比較して見ることができると、とても役に立ちます。

また、環境に変化がないにもかかわらず観測値に増減がある場合は、それは故障や障害の予兆かもしれません。一例を挙げると、IO待ちのプロセスが増え続けて高止まりしている場合は、ディスク故障によるIO性能の低下が原因かもしれません。

監視項目を概観

次に監視をする対象を元に分類して、監視項目を整理してみたいと思います(表1)。ちなみに、監視項目として挙げているのは筆者の環境で実際に行っているものです。

表1: 監視項目
サービス監視 ネットワーク ping疎通
HTTP HTTP疎通
HTTPレスポンス時間超過
MySQL MySQL疎通
レプリケーション状態
スロークエリーログ超過
リソース監視 サーバ メモリ使用率、使用割合
CPU使用率、使用割合
ロードアベレージ
ディスク使用率
ディスク使用量の増分
iノード使用率
ネットワークトラフィック量
ネットワークパケット数
メール キューに溜まっているメールの数
Apache httpdプロセスの状態(応答中、keepalive中、ログ書き出し中、アイドルなど)
Tomcat JavaVM(ヒープ領域の使用量など)
MySQL コネクション数
秒あたりのクエリ数
秒あたりのクエリ割合(SELECT、INSERT、UPDATE、DELETE)
各種キャッシュヒット率(key cache, query cache, thread cache)
テーブルスペースの使用量
memcached 空きメモリ量
ハードウエア監視 温度 lm_sensors, SMART(hddtemp, smartctl)
ECCのメッセージ
IOエラー

異常の通知

続いて、異常を検知した場合の「通知」について考えみましょう。

通知の手段

お手軽な通知の手段はメールではないかと思います。筆者の環境でも、緊急対応を要するものは、関係者の携帯電話へメールを送り、緊急度は低いけど対応が必要なものは、PCで読み書きするアドレスへメールで通知しています。

ただ、いちいちメールを見ないと通知が目に入らないのは面倒です。弊社では社内にIRCサーバを立てて意見交換などを行っているので、勤務中は常にIRCクライアントを立上げています。そこで、通知メールの内容をメッセージとしてIRCチャンネルにポストするスクリプトを書いて、通知メッセージに含まれる単語をIRCクライアントのキーワードとして登録しました。これで勤務中ならば、いちいちメールをチェックしなくても、IRCクライアントがポップアップするので監視メッセージが目に入るようになり、通知を見逃す可能性を低くすることができました。

メール以外の通知手段としては、USBやRC-232C、ネットワーク経由でPCから制御できる機器(注1)(図1)が考えられるのではないかと思います。

図1: USBミサイルランチャー
USBミサイルランチャー
注1
パトランプ、電光掲示板、(おもちゃの)ミサイルなどなど。

通知のコツ

さて、やみくもに通知をするのは得策ではありません。ここでは通知のコツをいくつかあげます。

レベルをわける

異常の重要度や対応の緊急度に応じて通知のレベルをわけて、レベルによって通知手段(携帯電話へのメールかPCへのメールかなど)を変えられるようにしましょう。

あまりレベルを細かくわける必要はなく、2〜3このレベルで十分ではないかと思います。

参考までに筆者の環境では表2のようにしています。

表2: 通知のレベル
レベル 内容 通知方法
emerg 今すぐに対応が必要な障害 携帯電話とPCへメール
warn 緊急性はないが、なにかしらの対応が必要な障害 携帯電話とPCへメール
info 障害の予兆など、対応の必要はないものの通知しておいたほうがよいもの PCへメール

不必要な通知はしない

「通知をしないより、とりあえず通知しておいたほうがいいのでは?」と思うかもしれませんが、必要のない通知はしてはいけません。なぜなら、不必要な通知に埋もれて緊急性の高い通知を見落としてしまう危険性があるからです。

特に、SWATCH(注2)などを使って、syslogを選別して通知するケースでは不要な通知をしがちになります。導入初期はしかたありませんが、不要と判断したらどんどんマスクして通知しないようにしましょう。これを面倒がって実践しないと、通知自体がおおかみ少年化してしまい無意味になってしまいます。

通知の間隔

通知は障害発生時だけでなく、障害状態の間は通知し続けるようにしましょう。

発生時に一度だけの通知だと、万が一それを見逃した場合、対応が送れてしまいます。

ただし、通知し続けるときは適当な間隔をおいて通知するようにしましょう。やたら間隔が短いと、DoSになってしまいますので。参考までに筆者の環境では、緊急性の高いものは30分〜1時間間隔にしています。

通知メールの文面

通知メールのSubjectは、障害の種類がわかる簡潔なものにしましょう。緊急度が高い場合は、先頭に「EMERG」とつけるのもいいと思います。

メールの文章には、障害対応の初動の助けとなる情報を簡潔にまとめましょう。定型の対応がある場合は、手順や投入するコマンドもあわせて記載しておくと、あわてがちな障害時にかなり役に立ちます。

それから、障害発生時の時刻もメール本文に入れておいた方がよいでしょう。

監視の具体例

監視にまつわる話はこのへんでおしまいにして、後半は実際に使っている監視機構を紹介したいと思います。

今回紹介するのは次の3つです。

  • hdmond ディスク使用量などの監視
  • Ganglia サーバリソースなどのグラフ化
  • apmond Apacheのプロセス状態のグラフ化

hdmond

hdmondは筆者が所属するチームのメンバが書いたPerlスクリプトで、ディスクパーティションごとに次に挙げる項目を監視します。

  • 使用率の超過 使用率が閾値(例えば90%)を越えたら通知をします。
  • 使用量の増加 監視間隔あたりに、ディスク使用量の増加が閾値を越えた場合に通知をします。 これは、使用率の超過では検知できないような事象、例えば、プログラムが意図しない動作をしてディスクを大量に消費しているような状態を、早い段階で検知する目的があります。実際にこれに何度か救われたことがあり、おすすめの監視項目です。 例えば5分間で500MB以上増加したら通知をするようなイメージです。
  • inode使用率の超過 ディスク使用率と同じように、inodeの使用率も監視しています。 サイズの小さいファイルを大量につくる場合、データ領域には余裕があるのにinodeが足りなくなってファイルが作れない、といった状況に陥る可能性があります。こんな事態を未然に防ぐのがこの監視項目の目的です。

閾値の設定方法

前節であげたそれぞれの監視項目の閾値は、外部の設定ファイルで指定できるようにしています。

パーティションごとに個別の閾値を設定できるのはまぁ当然として、時刻によっても閾値を変えられるようにしています。図2が設定の例で、書き下すとこうなります。

  • / パーティションについて、
  • 使用率の閾値を80%にする
  • 午前2時から4時の間だけは、使用量の増加の閾値を3000MBに変更する(これ以外の時間帯はデフォルトの閾値)

深夜から朝方は、バッチが走り昼間よりディスク使用量の増加が多いことがよくあります。こういったときに通知を抑制するために、時刻毎に閾値を変えられるようにしています。

図2: hdmondの設定例
/:
  everytime:
    used_ratio: 80
  2-4:
    delta: 3000

Ganglia

冒頭の「変動を観察する」の節でふれたように、サーバリソースなどをグラフ化しておくとなにかと役に立ちます。

グラフ化ツールいろいろ

さて、データ収集とそのグラフ化をやってくれるツールにはいろいろなものがあります。いつくかあげてみましょう。

MuninとCactiは実際に使ったことがあるのですが、Muninはとてもたくさんの種類のグラフが描けることが、Cactiはレイヤ(グラフ描写、データ定義、データ収集)がきれいに分かれていることと、その設定がすべてブラウザで行えることがいいなと思いました。

ただ、いずれも、監視対象となるノード(サーバ)を追加や削除した場合は設定を書き換える必要があったり、グラフ表示画面の一覧性がよくなかったりと、大量のサーバをモニタしたい場合にはちょっと不向きかなという印象を持っています。

大量ノード向けのグラフ化ツール

では何を使っているかというと、サーバファームではGangliaを使っています。

Gangliaは元々クラスタやグリッドコンピューティングといった、大量のノードがいる環境での使用を想定して作られたモニタリングシステムです。

実際に使ってみて「あぁ便利だわこりゃ」と思った点をあげてみます。

まず1つめは、ノードを追加、削除した際に設定変更が要らないという点です。追加したノードではエージェント(gmond)を動かすだけでOKです。これだけで、データ収集とグラフ化を行う役割のステーション(gmetad)と通信して、グラフ化対象となるグループに追加されます。通信はマルチキャストで行われるので、互いのIPアドレスを設定する必要もありませんし、ノードを検出するためにサブネット全域にSNMPしまくるといったこともありません。

2つめのステキポイントはグラフの一覧性です。図3を見てください。こんな風に全てのノードのグラフがグリッド状に表示されるので、ざっとながめて傾向を比較したりする際にとても見やすいです。

ほめてばかりではなんなので、逆に「あーここいまいちだわ」と思った点もあげてみます。

まず、グラフの種類が多くないという点です。CPUやメモリの使用率、トラフィックなど、基本的なグラフは描けるのですが、Muninほどその種類は多くありません。また、独自のグラフを追加する場合、値が1種類のものならばgmetricというコマンドで値を送信するだけでいいのですが、1つのグラフに複数の値を描きたい場合(例えばIO readとIO writeとか)は、Ganglie本体のコード(PHPで書かれています)に手を入れる必要があります。

2つめは、グラフの表示期間の指定の選択肢が固定で、1時間、1日、1週間、1か月、1年しか選べない点です。これでは「大量アクセスがあったあの日の何時から何時までだけのグラフを見たい」といった柔軟な表示ができません。ただ、観測データは全時間保存されているので、表示期間指定のユーザインターフェースと描写ロジックにちょっと手をいれれば、任意の期間のグラフを見られるようにできます。筆者の場合もそのように改造し、ついでにYahoo! UI Library(注3)のカレンダを使って日付の指定をしやすいようにもしています。

図3: Ganglia
Ganglia

apmond

最後に、Gangliaのカスタムグラフの例として、Apacheのプロセス状態のグラフを紹介します。

Apacheに付属するモジュールmod_statusを有効にすると、立ち上がっているhttpdプロセスの状態を知ることができます。(表3)

例えばhttpd.confにリストlist_modstatusと設定すると、http://example.org/server-statusというURLにアクセスすることで、これらの状態情報を見ることができます。また、/server-status?autoにアクセスすると、プログラムで処理しやすい形式でレスポンスが返ってきます。

そしてこの状態ごとに色分けして累積して描いたグラフが図4です。

こうやってグラフ化することにより、単純に「あぁWebサーバ忙しそうだな」という以上に、どんな処理をしていて忙しいのかがひとめでつかめると思います。

表3: Apacheの状態
記号 意味
_ 接続を待っている
S 起動中
R リクエストを読んでいる
W リプライを送っている
K keepalive要求のため待機している
D DNS問い合わせ中
C 接続を切断中
L ログ書き込み中
G 終了処理中(Graceful)
I アイドルワーカを整理中
. プロセス不在の空きスロット
リスト1: mod_statusの設定
<Location /server-status>
  SetHandler server-status

  Order Deny,Allow
  Deny  from all
  Allow from 10.6.25.0/24
</Location>
図4: Apacheプロセス状態のグラフ
Apacheプロセス状態のグラフ

おわりに

今回は「監視」について、その目的・手法などを紹介した後、実際の監視機構をいくつか紹介しました。

ネットワークもサーバも機械である以上、いつかは故障して止まります。それでもサービスはとまらないように各所冗長化するわけですが、想定外の故障のことを考えると停止の可能性がゼロになるわけではありません。そして万が一停止してしまったときに絶対に避けなければならないのは、「停止に気づかずに放置してしまった」という事態です。

ですので、監視のポイントは、異常を検知したらできるだけ速やかに担当者に通知を入れること、そして適切な対応をとれるように、必要な情報や対処法を提供することだと思います。

今回の内容がみなさんの運用監視の助けになれば幸いです!

今回のまとめ

  • 監視の目的は2つ
    • 異常を検知
    • 変動を観察
  • 異常を検知したら速やかに通知
    • 発生時刻、事由、定型の対処法など必要となる情報を沿える
  • 変動をグラフ化しておくといろいろと役に立つ
    • 後日、大量アクセス時の状態をふりかえる際など

コラム: ログの集約

たくさんのサーバがあり、そのそれぞれがログを出力している場合、どこか一か所にログをまとめられると便利です。

例えば、ロードバランスしているWebサーバがたくさんある場合、ターミナルをたくさん開いてそれぞれのサーバにログインしてログを見るより、全サーバのログを集約して1か所だけで確認できたほうが便利です。(tail -fでログが流れる様を見るのは爽快です)

ログの集約にはいろいろな方法があるのですが、ここではsyslog-ng(注4)を使ったApacheのログ集約の方法を紹介します。

まずはApacheの設定です。すでに通常のCustomLogディレクティブが設定されていると思うので、その下あたりにリストlist_loggerを追加します。これで、combined形式のApacheのアクセスログが、ローカルのsyslogサーバに送られます。loggerコマンドの-tオプションはログに追加されるラベルで、後ほどこのラベルを元に集約ログの出力先を変えますので、プロジェクト名などにしておくといいでしょう。

次にWebサーバ自身で動いているsyslog-ngの設定です(リストlist_syslog_web)。syslog-ngは、sourceでログの発生元を定義し、filterで取捨選択し、destinationでログを保存するファイルや転送するログサーバの指定をします。リストlist_syslog_webでは、ローカルで発生したログのうち、ファシリティがlocal6でログレベルがinfoのものだけを、log.example.orgというサーバに転送しています(注5)。

最後にログを集約するログサーバ、log.example.orgのsyslog-ngの設定です(リストlist_syslog_log)。まずsourceですが、先ほどと違って対象となるのはリモートから受け取ったログのみなので、s_remoteのように設定します。次のfilterはWebサーバのものと全く同じです。注目してほしいのは最後のdestinationです。fileで保存するファイルのパスを指定しているのですが、その中に$PROGRAMというのがあります。これはsyslog-ngのマクロで、$PROGRAMはloggerコマンドの-tオプションで指定したラベルに展開されます。続く$YEAR、$MONTH、$DAYはその時の年月日に展開されます。このような設定にしておくと、ApacheのVirtualHostごとにloggerの-tオプションの値を変えれば、syslog-ngの設定は一切変更する必要なく、ログサーバにアクセスログが集約され、しかもVirtualHostごとに別ファイルにすることができます。

注5
 ただし、UDPでログサーバにログを転送する場合は、UDPの特性上、ログが欠損する可能性がある点に注意してください。
リスト2: Apacheログの設定
CustomLog "|/usr/bin/logger -t foo -p local6.info --" combined
リスト3: Webサーバのsyslog-ng.conf
source s_local {
  internal();
  unix-stream("/dev/log");
  file("/proc/kmsg" log_prefix("kernel: "));
};
filter f_httpd {
  facility(local6) and level(info);
};
destination df_httpd_local {
  udp("log.example.org");
};

log {
  source(s_local);
  filter(f_httpd);
  destination(df_httpd_local);
};
リスト4: ログ集約サーバのsyslog-ng.conf
source s_remote {
  udp();
  tcp();
};
filter f_httpd {
  facility(local6) and level(info);
};
destination df_httpd_remote {
  file("/var/log/serverslog/realtime/$PROGRAM.acc.$YEAR-$MONTH-$DAY"
       perm(0644)
       dir_perm(0750)
       dir_owner(loggather)
      );
};

log {
  source(s_remote);
  filter(f_httpd);
  destination(df_httpd_remote);
};

この連載の記事一覧

参考図書

目次