更新日: 2023-11-07 19:20:41 +0900
公開日: 2011/05/25
発売日: 2007/8/24
この文書は2007/8/24に書かれたもので、ソフトウエアの名称、バージョン、設定項目、社名などの固有名詞などなどは当時のまま掲載しています。
ですので、インストール手順や設定内容は最新版のドキュメントを参照していただき、この文書からは理論や考え方、構成のヒントなどを読み取っていただければと思います。
今回は、スケーラブルなシステムそのものではなく、「監視」にまつわる話を書きたいと思います。
前半は監視について概観し、後半では実際に使っている監視のしかけをいくつか紹介したいと思います。
監視の詳細に入る前に、まずは「監視」という行為についてちょっと整理しておきましょう。
監視の目的は大きく分けると2つあると思います。
まず、「異常を検知する」ですが、これはみなさんが「監視」にもっているイメージそのままなのではないでしょうか。具体例を挙げると、
といったものが「異常を検知する」にあてはまります。
システムを運用するにあたり、「正常」な状態を保ち続けるのがその目的のひとつとなります。したがって、「正常」ではない「異常」な状態を検知することが必要となってくるわけです。見方を変えると、「異常を検知する」監視は、障害対応を開始するきっかけと考えることもできます。
次に「変動を観察する」です。具体的には、
といった値を継続的に記録し、視覚化し、傾向や変動をつかみやすくすることを意味します。
即座の対応が必要な「異常を検知する」とは違い「変動を観察する」は派手さはありませんが、実践しておくと後々、そのありがたさが感じられると思います。
例えば、メルマガやテレビコマーシャルや大手ポータルサイトへの広告掲載などといった、訴求活動をした場合、その瞬間に大量のアクセスが押し寄せてきます。アクセスが落ち着くまではあれやこれやの対応でいっぱいいっぱいなのですが、一段落してじゃぁどこがボトルネックになっていたのか?というときに、様々な情報の変動がグラフで比較して見ることができると、とても役に立ちます。
また、環境に変化がないにもかかわらず観測値に増減がある場合は、それは故障や障害の予兆かもしれません。一例を挙げると、IO待ちのプロセスが増え続けて高止まりしている場合は、ディスク故障によるIO性能の低下が原因かもしれません。
次に監視をする対象を元に分類して、監視項目を整理してみたいと思います(表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)が考えられるのではないかと思います。
さて、やみくもに通知をするのは得策ではありません。ここでは通知のコツをいくつかあげます。
異常の重要度や対応の緊急度に応じて通知のレベルをわけて、レベルによって通知手段(携帯電話へのメールかPCへのメールかなど)を変えられるようにしましょう。
あまりレベルを細かくわける必要はなく、2〜3このレベルで十分ではないかと思います。
参考までに筆者の環境では表2のようにしています。
レベル | 内容 | 通知方法 |
---|---|---|
emerg | 今すぐに対応が必要な障害 | 携帯電話とPCへメール |
warn | 緊急性はないが、なにかしらの対応が必要な障害 | 携帯電話とPCへメール |
info | 障害の予兆など、対応の必要はないものの通知しておいたほうがよいもの | PCへメール |
「通知をしないより、とりあえず通知しておいたほうがいいのでは?」と思うかもしれませんが、必要のない通知はしてはいけません。なぜなら、不必要な通知に埋もれて緊急性の高い通知を見落としてしまう危険性があるからです。
特に、SWATCH(注2)などを使って、syslogを選別して通知するケースでは不要な通知をしがちになります。導入初期はしかたありませんが、不要と判断したらどんどんマスクして通知しないようにしましょう。これを面倒がって実践しないと、通知自体がおおかみ少年化してしまい無意味になってしまいます。
通知は障害発生時だけでなく、障害状態の間は通知し続けるようにしましょう。
発生時に一度だけの通知だと、万が一それを見逃した場合、対応が送れてしまいます。
ただし、通知し続けるときは適当な間隔をおいて通知するようにしましょう。やたら間隔が短いと、DoSになってしまいますので。参考までに筆者の環境では、緊急性の高いものは30分〜1時間間隔にしています。
通知メールのSubjectは、障害の種類がわかる簡潔なものにしましょう。緊急度が高い場合は、先頭に「EMERG」とつけるのもいいと思います。
メールの文章には、障害対応の初動の助けとなる情報を簡潔にまとめましょう。定型の対応がある場合は、手順や投入するコマンドもあわせて記載しておくと、あわてがちな障害時にかなり役に立ちます。
それから、障害発生時の時刻もメール本文に入れておいた方がよいでしょう。
監視にまつわる話はこのへんでおしまいにして、後半は実際に使っている監視機構を紹介したいと思います。
今回紹介するのは次の3つです。
hdmondは筆者が所属するチームのメンバが書いたPerlスクリプトで、ディスクパーティションごとに次に挙げる項目を監視します。
前節であげたそれぞれの監視項目の閾値は、外部の設定ファイルで指定できるようにしています。
パーティションごとに個別の閾値を設定できるのはまぁ当然として、時刻によっても閾値を変えられるようにしています。図2が設定の例で、書き下すとこうなります。
深夜から朝方は、バッチが走り昼間よりディスク使用量の増加が多いことがよくあります。こういったときに通知を抑制するために、時刻毎に閾値を変えられるようにしています。
/: everytime: used_ratio: 80 2-4: delta: 3000
冒頭の「変動を観察する」の節でふれたように、サーバリソースなどをグラフ化しておくとなにかと役に立ちます。
さて、データ収集とそのグラフ化をやってくれるツールにはいろいろなものがあります。いつくかあげてみましょう。
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)のカレンダを使って日付の指定をしやすいようにもしています。
最後に、Gangliaのカスタムグラフの例として、Apacheのプロセス状態のグラフを紹介します。
Apacheに付属するモジュールmod_statusを有効にすると、立ち上がっているhttpdプロセスの状態を知ることができます。(表3)
例えばhttpd.confにリストlist_modstatusと設定すると、http://example.org/server-statusというURLにアクセスすることで、これらの状態情報を見ることができます。また、/server-status?autoにアクセスすると、プログラムで処理しやすい形式でレスポンスが返ってきます。
そしてこの状態ごとに色分けして累積して描いたグラフが図4です。
こうやってグラフ化することにより、単純に「あぁWebサーバ忙しそうだな」という以上に、どんな処理をしていて忙しいのかがひとめでつかめると思います。
記号 | 意味 |
---|---|
_ | 接続を待っている |
S | 起動中 |
R | リクエストを読んでいる |
W | リプライを送っている |
K | keepalive要求のため待機している |
D | DNS問い合わせ中 |
C | 接続を切断中 |
L | ログ書き込み中 |
G | 終了処理中(Graceful) |
I | アイドルワーカを整理中 |
. | プロセス不在の空きスロット |
<Location /server-status> SetHandler server-status Order Deny,Allow Deny from all Allow from 10.6.25.0/24 </Location>
今回は「監視」について、その目的・手法などを紹介した後、実際の監視機構をいくつか紹介しました。
ネットワークもサーバも機械である以上、いつかは故障して止まります。それでもサービスはとまらないように各所冗長化するわけですが、想定外の故障のことを考えると停止の可能性がゼロになるわけではありません。そして万が一停止してしまったときに絶対に避けなければならないのは、「停止に気づかずに放置してしまった」という事態です。
ですので、監視のポイントは、異常を検知したらできるだけ速やかに担当者に通知を入れること、そして適切な対応をとれるように、必要な情報や対処法を提供することだと思います。
今回の内容がみなさんの運用監視の助けになれば幸いです!
たくさんのサーバがあり、そのそれぞれがログを出力している場合、どこか一か所にログをまとめられると便利です。
例えば、ロードバランスしている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ごとに別ファイルにすることができます。
CustomLog "|/usr/bin/logger -t foo -p local6.info --" combined
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); };
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); };