失敗を学びに変える「障害報告書」の書き方 ─ RettyのCTOがGoogleで学んだ「問題を隠さない文化」
人間は失敗するものです。エンジニアもまたしかり。Retty株式会社の樽石CTOが考える、失敗を学びに変える考え方とノウハウを紹介します。
はじめまして。Retty株式会社でCTOを務める樽石将人(@taru0216)です。Rettyにおける技術の責任者として不確実性の高いシステム開発を成功に導くよう牽引したり、メンバーが働きやすくなるような仕組みづくりを行ったりしています。
子供の頃からパソコンに親しみ、新卒一期生でレッドハットに就職して、Rettyに入社するまでGoogleや楽天を経てきました。エンジニアとして活動して約30年。日々失敗し続けていますし、過去には大規模サービスを止めてしまったこともあります。
人間である以上、バグやエラーは必ず起こるもの。エンジニアは失敗を繰り返す仕事です。
失敗を糧として成功に変える秘訣(ひけつ)は、障害報告書を書く習慣をつけることです。私も仕事する上で実践していますし、Rettyのメンバーにも勧めています。とくに若手エンジニアにはぜひ身に付けてほしいと考えています。
この記事では、私が失敗の基準としている考え方と、障害報告書によって失敗を学びに変えるノウハウをお伝えします。
- どこからが失敗なのか?
- 私自身の失敗と学びの体験
- 障害報告書の書き方
- 「失敗を回避するための方法」にフォーカスする
- 失敗を振り返ることでポジティブなものにしよう
- 参考・監視サービスあれこれ
- 執筆者プロフィール
どこからが失敗なのか?
仕事に対して「完璧な達成」を目指す人は多いのではないでしょうか? まず、その思い込みを捨てましょう。ほとんどのWebサービスは「完璧」でなくてよいのです。
細かいバグがあったとしても、サービスを利用するユーザーさんが望む体験を提供できていれば、問題は起こりません。ユーザーさんに大きな影響がない状態にしておくことが大切です。
失敗とは何でしょうか? 私がその基準としているのは、品質レベルです。
コードを書けば、エラーやバグがあるものです。運営していると、想定外の問題も発生します。皆さんもプログラムが正しく動かなくて、ソースコードと格闘し、問題を解決するという日々を繰り返していると思います。
コードが間違っていても、品質レベルを保てているならば「失敗」ではありません。それでは、品質とは何でしょうか?
サービスレベル目標とサービスレベル指標
企業では、サービスレベル目標(SLO:Service Level Objective)として、具体的な稼働率を数値目標に使うケースが多いと思います。「稼働率〇〇.〇%」「レイテンシー〇〇msec以内」「エラーが発生した割合◯%以内」といった条件で表されます。
SLOを設定するために、サービスレベル指標(SLI:Service Level Index)を使います。これは、SLOの前提となる具体的な数値です。例えば、サービスの現在の稼働率が99.99%だったとすると、「99.99%」という数値そのものがSLIです。
このとき「稼働率が99.9%以上」がSLOだとすると「99.9%<99.99%(SLI)」となることから、現在のサービス状態は「SLOを達成している」と判断できます。
私が自分の仕事の品質を客観的に判断する際には、成果物(開発したコードや担当サービスなど)がSLO未達のときに初めて「失敗」と呼び、品質レベルを保っている限り、小さなバグやエラーがあっても「失敗」とは考えないようにしています。
ミスは起こるものなので、「少ない工数で品質基準を満たす」ことができる方法がないかを考えます。
致命的なミス(例えばユーザーさんの個人情報が流出)を防ぐ設計は、必ず必要です。守るべきものをしっかりと定義し、そうでないものはSLOに大きく影響するページ(=多くの人が訪れるページ)の品質を担保するよう丁寧な開発を心掛け、テストを細かく設定しましょう。
そうはいっても、どういった機能や技術コンポーネントがSLOに大きく影響しやすいかをバランスよく判断するには、経験が必要です。そこでオススメなのが、実際に失敗した後に「障害報告書」を書くことです。
障害報告書を書く2つの効果
障害報告書を書くことには、2つのメリットがあります。
まず1つ目は、自ら報告書を書くことで、周囲からの信頼回復の効果があること。私自身の失敗談でも触れますが、失敗が前向きな終わり方になります。障害報告書の完成度が高いほど周囲から敬意を持たれ、失敗前よりも信頼が得られる可能性もあります。
若手のエンジニアは、小さな失敗でも「失敗しました」とチームに宣言した方がよいでしょう。個人的には、いわゆる奇麗なソースコードよりも、品質の高い障害報告書を短時間で作成する方が圧倒的に重要と考えています。Rettyでも障害報告書を高い品質で、しかも迅速に書けるエンジニアを求めています。
もう1つは、障害報告書を書くまでの分析と調査によって学びがあり、同じ失敗をしなくなる効果があること。言語化することで経緯や対応策が整理され、今後同じ轍(てつ)を踏むことは防げるでしょう。
普段の業務では触れない部分も整理して言語化しなければいけないため、アーキテクチャやシステムの勉強にもなります。ぜひ、失敗した後の儀式として取り組むことをオススメします。
私自身の失敗と学びの体験
昔、大きなサービスを止めてしまったことがあります。
入社して研修を終え、本番環境を触れるようになった初日。ある実験をしようとして、サーバにコマンドを打ち込んだところ、本番環境の基盤になるプライベートクラウドを壊してしまいました。その基盤で動いていたサービスがすべて動かなくなってしまったのです。
自動復帰はしたものの、5分ほど止まり、100万リクエストが失われたと記憶しています。
原因は、サーバに打ち込んだ情報取得用のコマンド自体にバグがあったこと。軽い気持ちで「どのノードでどんなサーバが動いているか」という構成情報をDBサーバから取得しようとしたところ、コマンドが仕様通りに動かず、サーバが停止。サービスの動作も止まってしまいました。
今まで自分で大きな失敗をしたことがなかったので「これくらいでは壊れないだろう」と油断していた部分もあり、今だから笑い話にできるものの、そのときは肝が冷えました。
自動復旧して正常に戻ったことを確認した後、すぐに障害報告書を書きました。そして、問題が起きたことの報告と対処方法、次回以降の防止策をチームに共有しました(障害報告書の書き方は後で紹介します)。
かつては、失敗が起きるとチーム内の雰囲気が悪くなったそうです。しかし、私の報告を受けた当時のチームリーダーは「人間が失敗しても壊れないようなシステムにすべきだよね」とメンバーに言い、障害対応を終えたチームの雰囲気が少しだけ和やかになったのを覚えています。
Googleで学んだ障害報告書の意味
私が障害報告書を書いたのは、尊敬する優秀な先輩の失敗後の対応方法に感銘を受けたからです。
Google時代、失敗なんてしそうにない大先輩が、サービスを止めてしまったことがありました。失敗したことにも驚きましたが、もっと驚いたことが、先輩が障害報告書を書き上げる速さとその精度です。
エラーの発覚から数時間で障害報告書が社内に展開されました。報告書の内容は次の3つです。
- 根本原因の分析
- 再発防止策
- 時系列で、どんな行動をしたか
この失敗は、サーバの数が足りず、通信負荷に耐えきれなかった結果、サービス自体が落ちたというものでした。
報告書では、原因がキャパシティ計算にあったことを突き止めただけでなく、発生したエラーとその対応策をすべて時系列にまとめ、対応ノウハウを共有。メンバーが今後生かせるように情報をまとめてありました。
この失敗したときの効果的な対応方法を目の当たりにしてから、失敗しても大丈夫だと思うようになりました。
障害が起こっても障害報告書を書けばすべて丸く収まるという意味ではありません。障害そのものの原因を突き止め、再発防止策を考え、実行することに意味があるのです。
問題を隠さない文化とエラーバジェット
この先輩をはじめとして、Googleには問題が起きたことを隠さない文化がありました。
- 問題の根本となる原因を調べ、再発しないことを障害報告書で宣言し、実行する
- 障害報告書によって、チームに共有する
- 対応ノウハウを共有するほか、失敗を隠さず容認しあう文化をつくり、チームがより良くなる
Googleでは、障害報告書をポストモーテム(postmortem:事後分析)と呼び、チャレンジのために許容可能なエラー量を、エラーバジェット(Error Budget)と言いました。
エラーバジェットの数値は、エラーが起こるたびに減ります。エラーバジェットが残っているうちは、「チャレンジしてもよい」ことを意味します。
エラーバジェットを基準とする運用ルールは、例えば下記のように自分たちで決めることができます。
- エラーバジェットなし
- 障害報告書を書く
チーム全員でサービスをリリースする - エラーバジェットがあるうちのSLO未達
- 軽微な失敗として、障害報告書は書かない
このあたりのノウハウを学ぶ上で、他社の前例や指標を活用することはおすすめです。Googleでのシステム管理とサービス運用の方法論は『SRE サイトリライアビリティエンジニアリング』という書籍にまとまっています。
この本には障害報告書の書き方も掲載されています。ぜひ一度読んでみてください。
原著は、Webで無料公開されています。
Google - Site Reliability Engineering
現在のRettyで進めている施策
Rettyでも、皆に障害報告報告書を書くよう勧めています。
目的は、失敗を容認する雰囲気をつくること。誰かがミスをしても、同じ会社の同僚として失敗をサポートしようという気持ちを持つことが大事です。
Rettyでは、失敗を恐れて縮こまり、無難な目標を目指すのではなく、今までにない新しいやり方で世界を変えようとする行動を、積極的に評価しています。
こういったRetty独自の考え方を行動指針(Retty Way)としてまとめ、Retty Wayに沿って目覚ましい活躍をした人を四半期ごとに表彰しています。
挑戦は「Think Big」と呼ばれています。「Think Big」賞は、開発部門だけでなく、営業やコーポレート部門など全社員を対象に、大胆な目標を掲げて実行したり、長期的な成功に向けた発想や行動をしたりといった活躍をした人に贈られます。
障害報告書の書き方
いきなり「障害報告書を書け」と言われても難しいでしょう。「若手エンジニアにもこのくらいの障害報告書を書いてほしい」という気持ちを込めて、サンプルを公開します。
これは、Rettyで実際にあった「あるサービスが突然起動しなくなった障害」の報告書です。
原因は、誤って必要なファイルを消してしまったこと(「Root Causes」欄に記載)。障害の根本原因は非常に小さな問題でした。こういった小さな問題に気付くようになれば、確実に障害は少なくなっていきます。
ぜひ障害報告書を書く練習をして、安心感のあるエンジニアを目指してください。
「失敗を回避するための方法」にフォーカスする
サービスでは、アーキテクチャとシステム上に、二重三重のセーフティネットを用意していることが多いものです。障害が大きくなればなるほど、事前に兆候が現れます。どれか1つでもフラグに気付けば、大惨事にはなりません。
障害には、発生する根本原因(Root Causes)と、その原因が顕在化して障害に発展する引き金(Trigger)があります。例えば、CPUの負荷が上がった場合を考えましょう。
「CPUの負荷が上昇」という兆候があったときに、サーバ数を増やせば障害は発生しません。ところが、サーバ増設に時間がかかるようでは、急激に負荷が上昇したときに増設が間に合わず、障害につながります。
このとき、根本原因と引き金はそれぞれ次のようになります。
項目 | 内容 |
---|---|
Root Causes | サーバの増強に1時間かかる状態にあった |
Trigger | 負荷が急激に負荷が上昇 |
Root Causesが分かれば対処できます。この例であれば「サーバの増強時間を60分から10分にする」などの策を講じることができます。Root Causesの深掘りが弱いと、表面的な材料だけで対策を考えなければいけないため、具体的な対策からは遠のいてしまいます。
具体的には、Root Causesは内部要因にすることを心掛けてください。例えば、外部要因である「負荷が上昇した」をRoot Causesにするとどうなるでしょうか? 外部要因では、再発防止策を講じることができなくなってしまいます。こういう書き方は悪い例なので、しないようにしましょう。
設計時に取れる対策
設計時には、サービスに影響が出てはいけないのはどこか、クリティカルポイントを見極めることが大切です。まずは、ユーザーさんへの影響を最小限にする設計を目指しましょう。
バグがあってもユーザーさんが気付かなければよいと考えてください。例えば、ユーザーさんが使わないページのバグは、すぐに対処しなくても問題はありません。一方で、多くのユーザーさんが使うページについては、品質を担保できるようにします。
注力すべきポイントを見極めれば、どこを重点的に対策すべきか見えてきます。
目標を達成しやすくする設計方法を3つ挙げます。
- サーバ側が落ちてもアプリ側は動く設計にする
- こうすれば、ユーザーさんは影響なくサービスを使うことができます。具体的には、アプリ側でキャッシュし、その情報を表示する方法が考えられます。
- エラー部分の機能を分離、代替機能が動くような設計にする
- 具体例を挙げると、メールサービスで連絡先の一覧表示にバグがあっても、連絡先の検索機能が動いていれば、大半のユーザーさんに影響せずに済みます。多くのユーザーさんは「連絡先一覧が出てこないな」と思う程度でいてくれるものです。
- 新バージョンや新機能は、全体の10%に公開して様子を見る
- こうすれば、バグやエラーが起きても、影響を受けるユーザーさんを少なくできます。問題が起こらなければ、そのまますべてのユーザーさんに公開しましょう。
運用時に取れる対策
サービスの運用時に、失敗につながる兆候を素早く察知できれば、障害を未然に防ぐことができます。
ここでは例として、SLOを自分の行動に落とし込む方法を挙げます。まずは、SLIを毎日見るとよいでしょう。SLIがSLOに近づいていないか? その兆候を発見できれば、早めに行動できます。
例えば、サーバの応答時間が少しづつ遅くなっている場合、負荷が増えて、サーバの数が足らなくなっているのかもしれません。「SLIがSLOの80%に近づいたらサーバを増強する」といった意思決定をするとよいでしょう。
組織によっては、インフラチームや運用チームが業務の一環として監視を行っており、自分は監視にタッチしなくてよい場合もあるでしょう。それでも、担当するサービスが閾値を超えたか超えたないかくらいは見てもよいかもしれませんね。
突発的に発生する問題は、人間よりもシステムで発見できる体制にできるとよいでしょう。
毎日の測定には、監視ツールやソフトが使えます。開発時でも、サービスの状態をモニターで監視しつつ作業できます。値が変わったらアラートが鳴るよう設定すれば、確認リソースを割かずに済みます。
監視の際には、目標レベルを「正常」「ワーニング」「エラー」というように3つほど定めます。
緊急度に合わせて、通知方法も変えましょう。「ワーニング」に入ったら、Slackと、メールと、ブラウザのポップアップなどで通知。「エラー」になると電話が鳴る、などです。
「今の時代に電話?」と思うかもしれませんが、緊急時には普段と違う方法で通知される方が異変に気付きやすいものです。電話をよく使っている職場では、パトランプやサイレンで通知してもよいかもしれません。とにかく「気付く」ことを意識してください。
Rettyでは、監視ツールにPagerDutyを使い、エスカレーションモデルの障害通知システムを実現しています。エスカレーションとは、障害が発生すると一人目にまず通知し、その人が対応できない場合は二人目に通知する方法です。障害の一次受け対応を当番制にでき、エンジニアの負担が大幅に減ります。
障害発生時に取れる対策
再発防止を施しても、監視をしても、新たな障害が起こるときは起きます。その際は運営でカバーしましょう。エラー時もユーザーさんに落ち着いて行動してもらえるよう誘導します。
よく見るケースは、WebサイトやTwitterの公式アカウントで「ただいま問題が発生しています」とメッセージを出して、ユーザーさんに告知するもの。「いま使えるかどうか?」「運営は対応を始めているのか?」などの状況を知らせれば、安心してくれるユーザーさんは多いものです。
ユーザーさんが落ち着いていれば、エンジニア自身の心理的負担も減るでしょう。エンジニアも、落ち着いてエラー箇所を修正できます。
失敗を振り返ることでポジティブなものにしよう
チャレンジしたが故の失敗はあるものです。失敗を今後に活かすには、失敗を振り返ることが大切です。そのために障害報告書は有効な手立てとなるでしょう。
失敗の中にも良いところがあるはずです。失敗の中の光る宝石が利用できれば、失敗自体をポジティブなものに変えることができる。失敗が失敗でなくなります。
「若い人は失敗を恐れて挑戦したがらない」と言う人もいますが、いまの若い人たちの中には私の時代よりも意欲的で挑戦する人が多いように思います。起業家が多く、中には学生のうちから起業する人も。特にIT系は、日本でも投資のエコシステムができており、VC(ベンチャー企業向け投資家)が若い人たちにお金を出しています。
目標を高く持ち、どんどん挑戦してください!
参考・監視サービスあれこれ
「運用時に取れる対策」で、毎日の測定には監視サービスを利用できると書きましたが、参考までに代表的な監視サービスを3つ挙げておきます。
PagerDuty
- さまざまな監視ツールからのアラート通知を集約できる
- あらかじめ設定した目標レベルに沿って、電話、メール、チャットなどの通知方法を選択でき、スケジュールに合わせた通知も可能
Mackerel
- はてなが開発したサーバ監視サービス
- 通知方法(メールやチャットなど)を選択できるほか、解析結果のグラフ化もできる
Datadog
- 単一ホストからシステム全体までモニタリングできるサービス
- グラフも美しいと評判
執筆者プロフィール
樽石将人(たるいし・まさと/@taru0216)
編集:村山早央里(ZINE)