フィーチャーフラグは簡単ではない ~自分のせいで障害を起こしてしまった話
自分は巨大クラウドの開発者なのだが、先日自分のミスで障害を起こしてしまった。幸いなことに、お客様が気づく前に仲間がアラートで気づいてMitigate してくれた。この恥ずかしい失敗を世にさらして絶対に同じミスをしないようにしようと思う。
それはフィーチャーフラグをONにしただけ
私たちは定期的にサービシングループという期間があり定期的に回ってくる。その期間は開発をストップして、インシデントと呼ばれる障害の対応をする。ある時、自分がサービシングループの時にアラートが問題を検出した。原因を調査したら既知の問題で、既に対応もすんでおり、フィーチャーフラグをONにすれば、いつでもその機能をONできるようになっていた。
フィーチャーフラグというのは、DevOpsのプラクティスの一つで、ソフトウェアのスイッチをONにしたら機能を公開して、OFFにしたら機能を停止できる仕組みだ。
この仕組みを使うと、機能をリリースしても公開しなかったりもできるし、問題があった時の切り戻しもすぐに出来る。
Pragna は私に「あの機能リリースしといて」と言われた。私以外のメンバーは手が塞がっていたし、簡単に思えるお仕事だし、手が比較的空いていたシニアの私にお願いしたのだろう。正直プログラミングより面白くないし、本番環境に適用するときはセキュリティがきついのでいろいろめんどくさくもある。しかも誰でも出来ると思っていた。実際、特殊なマシンで、特殊な認証して、承認をもらってコマンドを流して、フラグをtrueに設定するだけなのだ。
エンジニアをやっているとこういう仕事はもちろんある。私はクエリを書いて、みんなにシェアした後、フィーチャフラグをON にした。ああ、くっそかんたんだ。誰でもできる。めんどくさいけど。と思いながら。
朝起きたら障害だった
次の朝に起きたら、なんと寝てる間に障害が起こっていた。それは土曜日だったけど、寝ている間に Pragna が障害対応してくれていたようですでにMitigateされている。お客様の報告ではなく、内部のアラートで検知した。
ちなみに我々はこういうことが起こっても被害が大きくならないようにカナリーデプロイメントという方式をとっている。一気に世界のリージョンに展開するのではなく、日にちをかけて、少しづつロールアウトする。そうすれば被害を最小限にとどめられる。
というわけで、最初のカナリーだったのと、内部アラートですぐに検出されたので、自分が「やってしまったぁぁ」とクッソ恥ずかしい思いをしたので、まだOn になったままだった他のリージョンのMitgationを進んで実施した。Pragnaが私に聞いた。UD0(つまりお客様への公開前の環境)でちゃんとクエリーした?と。私はしていないと答えた。なぜならアラートが自動的に検出してくれると思ったからだ。それでも Pragna は私を責めず、対応してくれてありがとうと言ったが、自分的には「うぉあああ、俺マジ三流だよなぁ」と思った。皆さんも私が講演で話したり、本書いたりしてるから、勝手に凄いエンジニアと勘違いしているかもしれないが何回も言うように私は一流目指して頑張ってる三流だ。だから、ちゃんとこの恥ずかしいことについて記録をすることにした。
くっそ恥ずかしい Root Cause
Mitigate した時点ではわかってなかったのだが、Root Cause は何だったのだろう。実は、boolean の値に対して、フィーチャーフラグは、`1/0` と `true/false` の設定が出来るのだが、その機能のコメントに`true/false` と書いてあったので、`true`を設定すると思い込んでいた。その機能を開発したのは自分ではないが、開発をした人もクエリーを見たが気づいてなかった様子だった。
サム・グッケンハイマーの一言
そういえば昔DevOpsエヴァンジェリストだった時に、サム・グッケンハイマーというDevOpsで著名な人と話している時に私が「フィーチャーフラグって簡単だよね」と言ったら彼は「フィーチャフラグは簡単ではない」と言っていた。それはもう何年も前だけど、今頃になって「もしかしてこれ?」と思い起こした。それを思い出してどうやったらこんなことが二度と起こらないか考えることにした。
フィーチャーフラグは簡単ではない
間抜けな自分はよくやることなのだが、「こんなん簡単や」と思う事っていろいろある。しかし、ソフトウェア開発には「簡単」というものは無いのかもしれない。
今回も「こんなん簡単でだれでもできる」と思っていた。なめていたといってもいいだろう。自分も一応フィーチャフラグが実装されているコードを読んで、こういう順番でフィーチャフラグをOn/Offすると新しい機能を安全に有効化できることまでは理解していたが、そこまでだった。だって、Onにするだけなんて簡単でしょって。
実際、Onにするのは簡単だろうが、今回の自分のミスは、振り返るとちゃんと理解してなかったからに尽きる。
これが自分の開発した機能だったらこうならないだろう。自分はコンテキストを知っているし、プライベートの環境で散々テストしているだろうし、尚且つ、自分が書いたフィーチャーフラグが`1/0` か`true/false`かなんて当然
知っている。
「やり方」だけでなく「コンテキスト」まで理解できているか
今回自分は自分が書いてない何年も前に実装されたコードを有効にした。確かに私は「やり方」だけを理解していた。しかし、本来ならば、人の代わりにやるのであれば、作った人と同じようなコンテキストの理解で仕事をすれば絶対にミスらないと考えた。だから、他人が書いた機能をONにする場合、自分がこんなことをするとそれに近づくことができるだろう
開発された当時の Pull Request を読んでコンテキストと実装を完全に理解する
Boolean の場合は、コードをクローンして参照して、1/0か、true/false か確認する
ログのコードを見つけて、正しく挙動したらこういうログが出てくるはずとあたりをつけてログのクエリーを書く
終わったらそもそも、1/0でもtrue/false でもどちらでも動くようにするPRを投げて次回からの問題を予防する
とこれぐらいやればよいだろうか。「やり方」がわかる場合に比べて時間はかかるが、やり直しのロールアウトの時のまずこれをやってみた。時間は2時間ぐらいかかっただろうか。でも自分の頭は明確であり、どうやってではなく、「なぜ」のレベルから理解できている。
そして、こういうログが来るはず。というログもクエリーをすでに作成しているので、準備も出来ている。
そして、やり直しのロールアウトの時には自信をもって、これで大丈夫と言えたのだった。
ところが落ちがあった
そこまで準備して、自分もこれでよいと確信があったのだが、Pragna が効いてきた。
「Placeholderの生成がちゃんとできてるか確かめた?」
ああ、やっぱわしはまだまだ三流だわ。しかし、がっかりせず積み重ねていこう。私は次のようなメモを One Note に書いて自分の Habit とするために書いておいた。
まとめ
ソフトウェア開発・運用では簡単な仕事などない。甘く見ていると足元をすくわれる。自分がコードを書いてない部分こそ自分がその開発者になったぐらい理解しているか確かめよう。
こんなダサい私ですが、先日こんな本を書いたのでよかったら読んでくだされ。