こんにちは、EC 事業部のフロントエンド・エンジニアのおいちゃん(@inouetakuya)です。先日、社内で Redis の障害を想定した避難訓練を行ったので紹介します。
背景
カラーミーショップ では、以前は Redis を利用していていましたが、ここ一年の間に用途が変わってきました。つまり、以前はコンテンツのキャッシュやセッションの保存先だったものが、いまでは非同期処理のためのキューとして使われるようになり、かつその処理には決済に関わるものも含まれています。
つまり Redis にダウンタイムが発生すれば、それがそのままビジネス面でのダメージに直結します。そこで Redis の自動フェイルオーバーを実現するため、インフラチームとともに Redis Sentinel の導入を進めてきました。
解決したい課題
Redis Sentinel を扱うのははじめてだったので、当初は「本当に自動フェイルオーバーするのか」を確認したいと考えていました。本番環境に投入する前に Redis Server の master インスタンスを一度落としてみて、それでもサービスは問題なく動くか確認してみようと考えました。
しかし、その確認手順を軽く GitHub の Issue に書き出しているうちに気付いたのは「自分たちが本当に確認すべきなのは Redis が自動フェイルオーバーするかということなんだっけ?」ということでした。Redis Server と Redis Sentinel を正しく設定しておけば自動フェイルオーバーはきちんと行われるはずです。もちろんそこも確認したい点のひとつではありますが、もっと重要なことがその先にあると考えました。つまり、
- どうやって Redis の異変に気付くのか?
- Redis の異変に気付いた後、開発チームはどのように行動すべきなのか?インフラチームはどうすべきなのか?
- 最終的にどのような状態にもっていければ障害対応が完了したといえるのか?
などなど、Redis そのものよりもそれを扱う運用面こそがぼんやりしていて、いざ障害が発生したときに適切な行動ができるか不安、というのが本当に解決したい課題でした。
避難訓練をやるぞ
「障害が発生したときに適切な行動ができるか不安」という課題に対しては、やっぱりやってみるしかないだろう、シミュレーションして行動してみるのが良いだろうと思い立ち、GitHub に「避難訓練をやるぞ」という旨の Issue を立てました。
それからインフラチームに「一緒にやりましょう」と声をかけて、「やりましょう!」と二つ返事をいただきました。すぐにそのようなリアクションが返ってくるのはペパボの仲間の良いところです。
また「避難訓練」は多くの人が小学校あたりから慣れ親しんでいるであろうワードだと思い、何かしらの反応を期待していましたが、そこに狙いどおり反応してくれるのも、ペパボの仲間の良いところです(笑)
避難訓練の内容
日頃、サービスに障害が発生した場合は、開発チームとインフラチームが連携して対応にあたっています。したがって、避難訓練も合同で行いました(私は開発チームのメンバーです)
(1) 障害のパターンとその対応についてディスカッション(15分)
まず想定しうる Redis の障害パターンと、その際にどう対応すべきかについて、インフラチームとディスカッションしました。
例えばダウンした Redis をどうにかして正常稼働させられるパターンと、稼働が難しいパターンがあるよねということを確認し、それぞれのパターンの対応方法を検討しました。
なお、ディスカッションのときには障害パターンの細部まで立ち入らなかったのですが、頭の中では下記のようなパターンを想定しつつ話をしていました。
- どうにかして正常稼働させられるパターン:
- データ設計を適切に行っていなくて、Redis がメモリ不足で書き込めなくなって落ちるとき。Redis を再起動させれば(一応は)動く(根本的にはデータ設計を見直す必要あり)
- 稼働が難しいパターン:
- Redis よりも下のレイヤーで障害が発生したとき
(しかしいま、文章を書きながら、データの不整合が発生したパターンへの対応は検討していなかったなということに気付きました。今後の課題とします)
(2) 対応手順をまとめる(15分)
ディスカッションした内容をもとに、対応手順を GitHub の Issue にまとめました。パターン別にやるべき項目を洗い出し、各項目の横にチェックボックスを付けました。開発チームはここをやる、インフラチームはここをやるなどの分担を決めました。
(3) 障害を起こして手順どおりに対応する(30分)
対象とした Redis Server 及び Redis Sentinel はまだ本番投入前だったので、今回の訓練は本番とほぼ同等の検証環境で行いました。Redis の障害をわざと起こして、作成しておいた手順どおりに対応していきました。
成果
手順にしたがって対応を進めていくなかで、手順があいまいな箇所や、想定どおりにいかない箇所が明らかになりました。
一例を挙げます。
まず前提として、Redis のインストールや設定を Puppet で管理していました。また Redis の挙動としては
- master がダウンして自動フェイルオーバーすると、slave インスタンスのうちのひとつが master に昇格する
- ダウンした master を再度起動させると、今度は slave として動くようになる
となっています。
しかし、Puppet マニフェストのほうは、元々 slave インスタンスを動かしていた Redis ホストのほうに(いまは master として動いているにもかかわらず)slave の設定を行うように記述していました。これをこのまま適用すると、master から slave に戻ってしまってアウトだから、自動フェイルオーバー後にも対応できる Puppet マニフェストの書き方にする必要があるということを確認できました。
このように、対応が必要な課題をあぶり出すことができました。
また、ここで見つかった課題を対応さえすれば、実際に障害が発生した際にもなんとか慌てずに対応できそうという安心感が持てました。これが一番の成果だったと思います。
そして、組織としてこれまで障害を防ぐためのプロセスや制御に力を入れてきましたが「それでも障害は起こる」いう前提のもと、「障害から速やかに復旧できるようにすることにもリソースを割いていく」きっかけになれば、ということも意識していました。
少しずつ広げていく
前述のとおり、今回は訓練を、本番環境ではなく検証環境で行いました。それでも大いに意義はあったと思うのですが、本番環境でやるとなると緊張感がまったく異なると思います。実施する時間帯を考慮しつつも(アクセスがあまりない早朝にやるとか)本番環境での訓練も実施したいです。
また今回訓練にあたったメンバーは比較的経験豊富なメンバーでしたが、研修のような位置づけで、経験が浅いメンバーがやってみるというのも学べるものが多そうな感触を得ました。
そして何より、今回のような取り組みを一回限りで終わりにせず、今後も継続的に続けていくことで組織が強くなれると考えました。
まとめ
さて、O'Reilly Japan - マイクロサービスアーキテクチャ で紹介されていたのですが、Google ではサーバー障害を模倣するような簡単なテストに留まらず、毎年、地震などの大規模な災害をシミュレーションした災害復旧訓練を行っているそうです。Netflix では障害を引き起こす(例えば無作為にマシンを停止させる)ボットを作成して、それを日常的に本番環境で実行しているそうです(まじか)
彼らとはサービスの規模もまったく異なりますが「障害は起こるもの。それを前提に障害に備える」というマインドは非常に参考にさせていただきました。
障害に強い組織をつくり、ユーザーにより大きな価値を提供できるよう、これからも精進していきたいと思います。