みどりねこ日記

よくわからないけど、頑張りますよ。

サービスに障害が発生したらどうしたらいいの?

どれだけ対策しようとサービスに障害はつきものですが、障害が発生したら損害が出るしユーザに謝ったりしないといけませんよね。 そういう非常につらい状況の中、障害からできるだけ早く復旧し、原因を究明して同じ障害が再び起きないよう対策を実施しなくてはならないわけですが、じゃあどうやったら効率的に調査できるの?という点についてまとめてみました。

障害つらいけどみんなで生きていきましょう。

なおこの記事は所属とか関係なく個人の見解であり云々ということを最初にお伝えさせていただきます。働き始めるとこういうところが心配になっちゃうんですね…。

あともっとこうしたほうがいいんじゃない?というご指摘があれば記事の内容を変更を検討しますのでぜひご連絡下さいませ。

障害は発生します

前提

まず前提としてですが、どれだけ信頼性の高さを謳っているハードウェアを使っても壊れる時は壊れますし、ソフトウェアには不具合があります。 ハードディスクは容量いっぱいになるし、OOM Killerはいつだって包丁を研いでいるし、データベースは操作ミスで全部消えることだってあります。 だから残念ながら障害が発生することは根本的に避けられません。 またユーザは原因についてはあんまり関心がありません。例えデータセンターにUFOが突き刺さったことが障害の原因だったとしても、重要なのはガチャが引けなくなったことです。 「オレのせいじゃないのに…」という気持ちは痛いほどわかりますが、何が原因であったとしてもサービス自体への影響を小さく抑えられるように頑張る必要があります。

事前の対策

ではどのような対策をしておけばいいのでしょうか。 例えばだいたいの場合において、バックアップとシステムの冗長化は非常に有効です。 定期的にデータのバックアップをしておけば、少なくともバックアップした時点までは復旧できるし、うまくシステムを冗長化しておけばシステムのコンポーネントのうち1個くらいに障害が発生しても何事もなかったかのようにサービスが継続できます。多分。 つまり原理的に障害の発生が避けられないなら、もう障害が発生することを前提としてシステムを設計しようよ、というわけです。

冗長化するということはコストが上がるってことでしょ?」という疑問は当然だと思います。 趣味で動かしているサービスとかだったら普段のランニングコストは抑えたいし、障害が発生しても「メンゴメンゴw」で済みます。 だからやりすぎればいいってもんじゃないという点については完全に同意です。 けど、エンタープライズならサービスが止まればサービスの信頼も落ちるし冗長化するために必要なコスト以上の損害が出るかもしれません。 なので、動かしているサービスの性質や、万が一障害が発生したらどれくらい損害が出るかを元に、どれくらいのダウンタイムが許されるのか、どの程度のデータの損失まで許されるのかといった見積もりをしてシステムを設計する必要があります。

復旧時間の短縮

障害が発生したときの対応を事前にチーム内で決めて共有しておくことで障害発生時の復旧を早めることができます。 復旧を優先するならその手順に従えばよいし、調査をする場合は何を見れば何を確認できるのかを事前に確認しておくことが重要です。 障害の影響度によって、とにかく復旧を急ぎたいのか、原因を調査するかは変わってきますので、この辺りの判断もできるだけ早く行いたいし、ベンダーのサポートに調査を依頼するときもこの辺の方針を一言入れておくだけで良い対応案を提案してくれるかもしれません。 また、あらかじめベンダーのトラブルシューティングや「よくあるご質問」のページへのリンクを共有し流し読みしておけば障害発生時に「あ、これもしかしてあれかな…」と手がかりが得られる場合があります。

システムの構成がどうなっているかについてもチーム内で共有しておくと原因調査に役立ちます。 システムの障害は、そのシステムに詳しい人がいる時だけに発生するとは限りませんから、文章としてシステムの構成を記録して残しておきます。 例えば、サーバのハードウェア構成とか、アプリケーションの正しい状態はこうだ、そしてそれらはこのコマンドを打てば確認できる、というような文章が共有されていれば、「そもそもこれは不具合なのか?」「何が期待される動作と異なっているのか?」といった点をすぐ判別することができます。 サーバが一般的でない構成となっている場合は、その背景についても共有しておきます。 変な設定になっていたりすると「こいつが原因なんじゃね?」という偏見観点で調査をしてしまいがちですが、背景が納得できるものであればうまく切り分けができるかもしれません。 また背景がわかっていたら後々もっと良い構成を取ることができるようになるかもしれませんしね。

テスト

システムのテストもしておきます。 障害に対する準備ができたと思っても、実際に障害が発生した時にうまく対応できなければ効果がありません。 一部のコンポーネントを落としてもサービスが継続するか、ネットワーク通信が遮断されても他のエンドポイントへ切り替わるか、バックアップからの復旧にはどれくらいの時間がかかるのかなど確かめておくと、いざという時に慌てなくて済みます。

メトリクスとログ

障害に対応するためには当然ながら障害が発生したことを検知しなければなりません。 サービスは動いているのか?ネットワークに問題はないか?ハードウェアに異常は発生していないか?パフォーマンスは足りているのか?といった観点でチェックを定期的に行なって、異常な状態となったことをできるだけ早く検知します。 また、検知したときに自動的に復旧したりフェイルオーバーする仕組みを取り入れておけば、人が作業する時間を短縮できるのでそのぶんダウンタイムを減らせます。

最後に、ログは非常に重要です。できる限り取りましょう。 こいつがないと一体何が起きていたのかわからず大体の場合迷宮入りすることになります。

障害が発生したときの事前の準備はとても大事です。面倒ですけど頑張りましょう…。

障害が発生したら

障害が発生したら、まず何が起きているのかや影響はどれくらいなのかを確認し、復旧か原因調査のどちらを優先するかを判断していきます。

復旧を優先するのであればバックアップからデータの復元を行なったり、スタンバイへ切り替えを行ったりすることになります。 ただ、原因がわからない以上復旧しても再発する可能性はあるので、復旧を優先したとしても原因究明は必要です。

じゃあどうやって調査していくの、という点ですが、まずはどのような障害が発生していたのか?の詳細を確認していきます。 障害が発生していた、ということは何かを元に障害と判断したということなので、メトリクスなりログなり、ユーザからの問い合わせなりを確認します。

障害調査に必要な情報

障害調査を行う上では、以下のような情報が重要になります。 この辺の情報は時間が経つにつれ記憶が曖昧になったり、取得ができなくなったりするので、できるだけ早い段階で記録しておきます。 ベンダーのサポートに調査を依頼するときもこの辺の情報を要求する場合が多い、というか必須なので、できるだけ少ない往復で解決したいのであれば初回の問い合わせでこの辺の情報と合わせて、どこまで調査したかを伝えるのが良いです。

  • 事象の詳細
  • 事象の発生日時。いつからいつまで発生していたのか、今でも発生しているのか
  • 何を元に障害と判断したか
  • エラーメッセージ
  • システムログ
  • アプリケーションログ
  • 各種メトリクス
  • OSやアプリケーションのバージョン
  • システムの構成
  • ネットワーク周りなら通信相手の環境など
  • 再現性。同じような環境でも発生するのか、そのマシン固有なのかなど
  • 心当たり(直前にシステム構成を変更したりパッケージのアップデートを行ったなど)

事象の詳細って何?

事象の詳細や日時については、例えば「SSH接続できない」という事象でも「他のマシンからは接続できるけど一部の環境からは接続できない」のか、「マシンへの疎通性がそもそもないのか」で全然違うものなので、できるだけ詳しく記録します。 ssh -vvvの出力はどうなっているのか、サーバ側のsshdは正常に起動しているのか、そのマシンで動いている他のアプリケーションは動作しているのか、ファイアウォールの設定はどうなっているのか、/var/log/secureはどうなってる?そもそもネットワークに繋がっているのか…といった感じで、色々確認していきます。

判断の根拠

何を元に障害と判断したか、というのは、だいたいの場合エラーメッセージだったりログだったり、メトリクスに異常な値が記録されているから、という答えになるかと思います。 障害の発生を判断するためには、「本来あるべき形」というものがわかっている必要があります。 「メトリクスが変に見えるから障害」というのは早計な場合があって、例えばストレージへの書き込みやネットワーク通信の量に異常に大きい値が記録されていても、実はバッチ処理を裏で動かしていただけだったり、アクセスの量が増えただけかもしれません。 CPU使用率が跳ね上がっていても、実はアプリケーションが正常に動作しているだけで、サービス自体には影響がなかったかもしれません。 この辺の判断は難しいので、複数のメトリクスを見つつサーバのキャパシティを大きくしたりしてどのように変化するかなど確認していく必要があります。

調査

実際の作業としては、事象が発生していた日時のログとそれぞれのメトリクスを眺めながら、相関らしいものがあるか、謎のエラーメッセージがあるかなどを頑張って見つけていくことになります。 Linuxであれば、syslogや/var/log/messages、/var/log/secure、/var/log/ntp.log、sysstatの結果、WindowsならApplication.evtx、System.evtxなどのログを取得します。 ipmitoolが使える環境なら、ハードウェア側に問題があったかなどを確認することもできますので設定しておきましょう。 OS上のログだけではなく、例えばZabbixなどの記録があればそれらも含めて何が起きていたのかを精査していきます。

OSやアプリケーションのバージョンに依存して発生する不具合もあります。 この辺りも記録して、似たような事象が報告されていないかを公式フォーラムなどで確認します。 それと使っているアプリケーションのバージョンはできるだけアップデートしましょう。 古いバージョンを使い続けることは、とりあえず動くという意味で楽ではあるのですが、セキュリティ上のリスクがあったり機能の制限があったりしてだんだん不便になってきます。サポートもいずれ切れます。 バージョンがものすごく古くなってから最新のものにアップグレードするコストは大きくなりがちで、そうなると「もう移行無理です」みたいな状況になるかもしれません。色々なしがらみがあって大変だろうとは思いますが、マメにアップデートできるよう頑張りましょう。 なおバージョンを変更する前には必ずバックアップをとって不測の事態に備えておきます。

システムの構成や通信相手の環境が原因で発生する障害も少なくありません。 エラーから「こいつが原因じゃね?」とサーバ側の設定を疑っても問題が見られない場合は、もうちょっと広い視点を持って、例えばアプリケーションが利用するAPIサーバとは正常に通信できていたのか、社内のネットワーク設定やファイアウォールに変更がなかったかといった観点で見直してみましょう。

それでもわからないとき

以上を実施したけど全然わかんねえ、という場合は各ベンダーの技術サポートにぶん投げてみましょう。 もしかしたら何かいいアドバイスをくれるかもしれません。なお技術サポートはだいたいの場合サポート範囲があるので、その範囲内での質問にしましょう。 あとサポートも人間なので、できるだけ紳士的に問い合わせましょう!

原因究明したら

原因がわかったらなんらかの対応が必要になります。 まずユーザへ影響があったなら、早めに謝罪をします。また、可能な範囲で影響範囲と当面の事象のワークアラウンドについてアナウンスをします。 その次に、サービスへの影響度とコストから、そもそもこれは対応が必要なのか、どのような対応を行なっていけば良いかという点について考えていきます。 対応が完了し次第、事象から得た教訓と対応をドキュメントにまとめて一旦収束…という形にしたいですね(願望)。

「なんか障害起きてたけど全然わかんねえ、どうしたらいいんだ」という場合は、なぜ切り分けができなかったかということを考えて、それを元に再発した時に調査できるようログの設定やメトリクスの追加をしておきます。 また、何度も障害が発生するのであれば、障害が発生していた時の共通点を見つけるために発生日時やログ、メトリクスを収集しておきます。 いつか原因わかるといいですねって感じですが、気長に頑張っていきましょう。

頑張っていきましょう

だいたい上のような対応になるかと思いますが、何か「変じゃないこれ?」みたいな部分があったらお知らせいただけると幸いです。 障害はつらいけど一緒に頑張っていきましょう。