Web サービスのシステムトラブル対応チェックリスト

遅れました。

この記事は
[クラウドワークス Advent Calendar 2015](http://qiita.com/advent-calendar/2015/crowdworks)
の24日目の記事でした。（遅れてごめんなさい！！）

「クリスマスは24の日没から25の日没までだから、 `DateTime#is_xmas?` を実装するときは注意しようという」記事は、売れ残りのケーキ並みに恥ずかしいのでお蔵入りさせるとして、

運用中のWebサービスでシステム障害が起きたときの私家版チェックリストを公開してみたいと思います。

これが正解というわけではなく、人によっていろんな調べ方があると思いますので、一例として参考にしていただければ幸いです。

- [ ] 本当はシステムトラブルが起きていない
    - [ ] 自分のブラウザでもアクセスできる（社内ネットワーク）
    - [ ] スマホの4G回線などで社外からのアクセスを試しても、アクセスできる
    - [ ] twitter や 2ch でも「アクセスできない」と書いている人がいない
    - [ ] ホスト名の解決はできている
    - [ ] リクエストは帰ってきている
- [ ] Webサーバは正常
    - [ ] ELB にてサーバがぶら下がっている
    - [ ] ELB にて out of service と表示されていない
    - [ ] Web
    - [ ] すべての Web サーバに ssh でアクセスできる
    - [ ] ロードアベレージが異常ではない
    - [ ] ディスクアクセスが刺さっていたりしない
    - [ ] メモリが枯渇していない
    - [ ] アクセスは来ている
        - [ ] HTTP サーバ
        - [ ] アプリケーションサーバ
    - [ ] アクセスはさばけている
        - [ ] 大半は 200 OK とか。
        - [ ] 大半は 500ms 以内
        - [ ] エラーログはあまり流れていない
- [ ] DB サーバは正常
    - [ ] cpu 使用率は正常
    - [ ] swap 発生してたりしない
    - [ ] Too many connections が出てたりしない
    - [ ] プロセスリストに変なプロセスが溜まっていない
    - [ ] スロークエリログにいっぱい流れてたりしない
    - [ ] エラーログにも何も記録されてない
- [ ] その他サーバは正常
    - [ ] キャッシュサーバ系もちゃんと立ち上がってる
    - [ ] 動いている
    - [ ] 外部 API サービスも動いているっぽい

## 本当にシステムトラブルが起きているか

念のため確認しましょう。もしかしたら気のせいかもしれません。


まず、おちついて自分のブラウザで本番を開いてみます。
開けなかった場合は深呼吸してもう一度です。

２連続で開けないなら、システムトラブルです。周りに大きな声で伝えましょう。

システムトラブルは平時ではなく有事なので、次の観点が大事です。

* 大抵の場合は、システムを復旧させるのが主目的です
* スピードが大事です
* 大抵の場合、思ったよりも広範囲の意思決定が求められます
* だれもリーダーシップを発揮しない場合、自分でやるしかありません

さて、自分のブラウザでも本番を開けない場合、下記のどのような挙動を示すかによってまずは問題の切り分けができます。

* リクエストが帰ってこないのか
* 画面が真っ白なのか
* サーバが見つかってないのか
* 全然関係ないページが開くのか

上２つはロードバランサーから内側の障害ですが、下の２つは名前解決的な障害なので厄介です。route53 を使っているなら設定を見直してみましょう。

自分のブラウザで本番が開ける場合、

* 社内・社外による違いはあるか
* 一部ユーザに障害が起きているのか・全部のユーザに障害が起きているのか

を把握しておきましょう。

## Web サーバは正常

次にロードバランサーのステータスをみてみましょう。
ELB を使っているなら、まずはサーバがぶら下がっているか確認しましょう。１台もサーバがぶら下がっていないなら、ぶら下げ直すところからスタートです。

流儀にもよりますが、私は原因追及よりもまずはサービス復旧を優先させる方が好きです。

ぶら下がっているサーバが out of service になっていないか確認してみましょう。 out of service になっているのならば、サーバが起動しているか確認しましょう。

事故により、仮想サーバを止めてしまったり、消してしまったりということは起こりえます。それらの事故がおきていないことを一つづつ確かめてみてください。

Web サーバが全て正常そうであれば、cpu 負荷と IO 負荷、メモリ使用状況をみてみましょう。

クラウドウォッチや munin など監視サービスを組んであればそれをみましょう。
ないならそれぞれのサーバに入って次のコマンドを軽く見てみましょう。

複数サーバに ssh するツールは幾つかありますが、私は [csshX](http://blog.matsumoto-r.jp/?p=3182) を使っています。

コマンドも幾つかありますが、私は `top` コマンドの上２行に記されている Load Avarage を軽く眺めて cpu 負荷を把握した後、 `vmstat` コマンドの `b` `bi` `bo` あたりを見ます。特に、 `b` 欄は IO 待ちプロセス数なので、数が多ければこれが原因です。`free` コマンドでメモリ使用状況も確認しておきましょう。 `free` コマンド実行結果の `free` 欄が 0 なら、メモリが枯渇しています。

サーバのリソース状況に問題がなければ、HTTP サーバにアクセスがあるかを確認しましょう。確認は `tail -f /path/to/log` で十分です。

アクセスが通常通りある場合、レスポンスのステータスコードの概観と、レスポンスタイムの概観を把握しておくことが大事です。
500 エラーまみれとか、すっごい時間かかってるやつだらけとかぱっと見異常なのか、それとも、なんか全部正常なのかによって判断が異なります。

アクセスログ以外に、エラーログの確認も念のためしておいてください。アクセスログよりも流量が多くないと確認しておいたほうが安心できます。

## DB サーバ

DB サーバも、まずはリソースのチェックからです。cpu 負荷、IO負荷、メモリ使用状況を見ておきます。

DB サーバは RDBMS によって違いますが、 MySQL や RDS の場合は次の３つを順番に確認してみましょう。

`too many connections` は大抵の場合、アプリケーションサーバのログか http サーバのログに出ているはずです。
この場合は、mysql につないで `show global variables like '%max_connection%';` し、アプリケションサーバ１台あたりのコネクション数と、アプリケーションサーバの台数を掛け合わせた数字と比較にしてみてください。なお、この時そもそも mysql につなげられなければ（なおかつその時のエラーメッセージが too many connections なら）原因が特定できたことになります。

次に変なプロセスがいないか確認してみてください。`show processlist` です。
なんかいっぱいプロセスがいた場合は、とりあえず殺すなり（殺す場合は、メモ帳にコピペしておくと、のちの原因追及に便利です）殺すなりしてみてください。

プロセスに原因がなさそうなら、スロークエリを見てみましょう。いっぱい出ているようであれば、そのクエリ発行部分をなんとかします。
最後にエラーログをみて、エラーが起きていないか確認しましょう。

## その他サーバ

基本的には Web サーバや DB サーバと同じく、サーバ資源の確認、cpu, io, メモリの使用状況を確認し、異常がなければ各サーバアプリケーションの使用状況確認であることは変わりがありません。
キャッシュサーバ系は死んでれば立ち上げ直すくらいの心構えが良いでしょう。

memcached が落ちてた時の原因特定などは、重要ですが、結構骨が折れるので、障害対応中に行うことはお勧めしません。（復旧を最優先にしたほうが良いでしょう）

## 最後に

障害復旧は、基本的ユーザーよりから攻めていったほうが有利です。

ここまで見てきたとおり、名前は解決でき、ロードバランサーも動いており、Webサーバもアプリケーションサーバも正常。その上 DB もキャッシュ系も全部正常な状況下で、それでもシステムトラブルに陥いるというのはあまりありませんので、事例がありましたら編集リクエストや Qiita などで事例共有いただければ幸いです。