運用の視点での機能レビュー
「運用の視点での機能レビュー」って意外と抜けがちなのでは、と思ったので自分のレビュー観点をまとめた。 運用の視点でレビューしようにも、どうしたら良いか分からないという人に共有する目的で作った。
「コード」レビューではなく「機能」レビューとしたのは、観点がコードにとどまらず、設計やドキュメントまで多岐に及ぶから。
まえがき
自分のこと
一応Web自社サービスのSRE。サイトの信頼性を高めることが主業務 監視系を頻繁にいじっている関係でアラートが上がった時によく対応している なぜ運用の視点が大事か
サービスは運用が開始してからが本番だから
サービスの開発に仮に1年かかったとしても、運用はサービスが終了するまでずっと続く
つまり運用する時間のほうが開発する時間よりもずっと長い
2年か、5年か、10年か、あるいは永遠にか
言い換えると運用を見据えた作りになってるほうが費用対効果が高い
※受託開発で開発と納品までが契約で、運用は別会社とかってケースだとこの限りではないかもしれないが
運用が開始してからプログラムを改修するのは難しい。なぜならすでにユーザがいるから
本番環境で稼働し始めるとサービスの性質によるが24時間使われる可能性がある
ユーザがいる状態で運用改善のための改修を当てるのは往々にして難しい。あるいは手間がかかる
サービス断が発生しないように段階的なリリースを踏む場合がある
メンテナンスに入れないとダメなケースもある
障害を起こしてからでは遅いから
障害の影響度にもよるし、障害は無くせないもの。でも障害は少ないほうが絶対に良い
平均故障間隔(MTBF)が短いほどユーザはサービスから離れていく
平均修復時間(MTTR)が長くなれば長くなるほどユーザはサービスから離れていく
障害とまでいかずども性能劣化でレスポンスが悪くなってもユーザは離れていく
これらの問題を完璧に未然に防ぐことは難しいけれど、意識するのとしないのとでは全く違う
運用の視点でレビューをする第一歩
アラート対応をしよう
アラート対応をすると大体問題が見つかる
調査に欲しいログが無い
ログメッセージが雑で何のエラーなのか分からない
アラートの緊急度・影響度が分からない
対応方法が分からない
これらの問題はなぜ起きるのかというと、実装者は自分がアラート対応をすることを考えていないから
アラート対応をしてみることで、アラート対応するときにどういった情報が必要か分かっていく
実装する時から運用を見据えた作りを開発者全員が意識するようになっていければ良い
監視システムを触ろう
監視システムに触ることでいろんなものが見える
すでに監視されているものが何か
何の監視が足りていないか
アラートを設定する時にしきい値をどう設定するか
妥当なしきい値とは何か
これは後述するけれどSLOが決まってるかどうかにも関わる 監視するのにどういった情報が必要か
監視システムから扱える形でログを出力するにはどうすればよいか
例えばログの書式
フリーテキストかJSONか
最近の監視系は標準でJSONパーサを備えてることが多いのでJSONが使えるならJSONにするべき
フリーテキストのログの場合ログパーサを自前で定義する必要がでてくるけれど、これはやめたほうが良い
JavaのスタックトレースやGoのパニックログなど、複雑なテキストが来た時にパースに失敗する場合がある パースに失敗するとログが適切なログレベルと判定されずに、アラートが上がらない場合がある
監視のことが全く分からない人は入門監視を読むのがオススメ 運用作業を知ろう
サービス運用をしてると不定期に特殊なオペレーションが発生する
メンテナンス
期間限定のキャンペーン
こういった特殊なオペレーションに対応できる作りを意識しないといけないわけだが、意識するには運用を知っていないといけない
人に聞こう
アラートのことも監視のことも運用作業のことも全く知らないのであれば、まずは聞くことから始める
聞いたらだいたい教えてくれる
会社が違うとかで守秘義務の都合で教えられない場合はあるかもしれない
教えてもらったらちゃんと感謝をしよう
本題
より具体的なレビューの観点を書いてく。僕が普段意識してることを片っ端から書いた。
これを全部達成するのは難しいし、僕も工数都合で全部達成できたものは多分無いけれど、なるべく意識している。
全般
機能全般にいえること
ログ
処理が正常終了したことをログに出力しているか
処理が異常終了したことをログに出力しているか
処理している、あるいは処理済みデータのIDはログに出力しているか
何を処理してたか分からないのは辛い
そのログメッセージから何が起きているか理解できるか
ログの目的は「ログを出すこと」ではなく、「何が起きているか伝えること」
errorみたいなそっけない文字列とスタックトレースしか出てないと何が起きているか伝わらない
トランザクションIDをログに含めているか
一連の処理の中で複数のログを出力する場合、ほぼ同時に複数の処理が走ると複数のログが混ざって処理のつながりが分からなくなる
複数スレッドで処理するWebサーバや、バッチをスケールアウトさせて並列に動かした時に問題になる
一連の処理の開始時点でトランザクションIDという一意なIDを発行し、ログに付与することでログが混在しても追跡できるようになる
不要なログ(デバッグログなど)を出力していないか
ログを追跡する時に邪魔になる。障害時に邪魔なログがあると復旧までの時間が伸びる
ログを保管するためにストレージを無駄に使うし、SaaSとかだとログイベント単位で課金が発生したりするので、余分なコストになる
ログが多すぎないか
コストに響く
そのログが本当に必要なものしか無いのであれば、ログが多いことは問題ではない
秘匿情報をログに出力していないか
見えちゃまずいものは隠すか、出さない
想定範囲の異常系のログはクラッシュログと区別して出力しているか
想定されるエラーの場合、適切なメッセージと共にログに出すべきで、横着してスタックトレースをそのまま吐くべきではない
スタックトレースをログに出す場合は、捕捉しそこねた想定外のエラーのみにするべき
適切なログレベルを使用しているか
INFO、WARN、ERRORは使い分けよう
人間が識別しやすいのもあるが、監視系からログを見る時に、ログレベルで集計するのにも使う
(可能なら)JSON形式のログにできるか
フリーテキスト形式のログの場合、監視系にログをパースする設定を仕込む必要がでてきてめんどくさい
そして独自形式のフリーテキストの場合、ログのパースに失敗することがある
JSON形式の場合、監視系が標準でログパーサーを備えている場合が多い
監視系の標準ログパーサーにログ書式をあわせるのがベター
もし監視系がJSONのログパースをサポートして無くて、監視系独自の書式のみサポートしてたりするなら、サポートしている書式に合わせるのが良い
いずれにせよ、自前でログ書式を設計して、ログパース設定を自分で設定するのは不毛なのでやらない方が良い
意図的に異常系を発生させて出力されたログから問題の発生した箇所を特定できるか
実際のところ追跡できるかどうかは追跡してみないと分からないので、ローカルで実際にエラーを起こしてログを追跡してみるのが良い
ローカルでログの追跡ができなかったなら、それは本番環境でも追跡できない
性能を評価できる情報をログに出力しているか
「監視」で後述
拡張性
機能をスケールアウトさせた時に異常が発生しないか
性能が足りなくなったら台数を増やして対処するのはよくやる
台数が増やされる前提で実装されてないといけない
あとAWSだとイベントをトリガーに起動する系だと多重起動する可能性があったりするので、それとの兼ね合いもある 実際にスケールアウトして動作させて、問題が起きないことを確認したか
安全な停止
安全に停止する方法は用意されているか
デプロイで処理が中断されることを考慮しているか
シグナルを受けて安全に停止できるか
シグナルを受けてから「何秒間停止するまで待機するか」を把握しているか
supervisordとかだとデフォルトではSIGTERMを送ってから10秒間待機し、それまでに停止しないとSIGKILLでプロセスを止める 例えば、SIGTERMからSIGKILLまでの待機時間が10秒の設定で、アプリケーション側では停止するのに最大10秒以上かかるような作りの場合、シグナルを受けて安全に停止しようとしても先にSIGKILLで殺されることがある
こういう場合、SIGTERM→SIGKILLまでの待機時間を、アプリケーションが安全に停止する時間よりも長い時間に設定しないといけない
安全に停止する方法をドキュメントに明記しているか
監視
監視アラートを設定しているか
その監視アラートを不要にするためにアプリケーションを改修できないか
アラートは「人間の対応が必要なもの」のみにするべき
バグを残して手順書で復旧するのではなく、バグを直すべき
あるいは、問題が起きた時に復旧するプログラムを別途作成して、自動で復旧するようにするべき
対応手順書へのリンクは記載されているか
アラートの緊急度はアラートか手順書から判断できるか
急がなくて良いならゆっくり対応したい
いつまでに対応が必要か判断できるか
翌営業日対応で良いならそうしたい
本当に人間の対応が必要なものか
無視して良いアラートが大量にあると、人はアラートを見なくなる
他のアラートで代用できないか
アラート設定は数が増えがちなので、ありものでまかなえるならそうしたい
死活監視をしているか
機能が正常に稼働していることを監視できているか
機能が停止していることを異常として検知できているか
エラーログしか監視していないと「動いていない」ことを検知できない
エラーが発生した時に異常として検知できているか
クラッシュ時のログのパースに失敗して監視系がエラーと判別できないことがある
性能監視をしているか
サービスレベル指標(SLI)は定まっているか
秒間リクエスト数
データ処理件数
レイテンシ
エラーレートなど
サービスレベル目標(SLO)は定まっているか
1秒以内に処理を終えないといけないのか、10分かかっても良いのか
検証環境等で実際に稼働させて監視系から動作を確認したか
負荷
どの程度DBに負荷が発生するか把握しているか
SQLにインデックスが貼られているか
インデックスが効くことを確認したか
EXPLAINしよう
外部(DB含む)へのリクエストがどの程度発生するか把握しているか
そのリクエスト量は許容範囲内に収まっているか
APIレートに引っかかる場合があるし、単純に迷惑かけちゃう可能性もある
データ件数が増えた場合を想定しているか
検証環境ではデータが少ないけれど、本番だとデータ量が多くて過負荷になって死ぬ、とかありがち
検証環境等で実際に稼働させて監視系から負荷量を確認したか
コスト
どの程度コストが発生するか見積もったか
コストを抑えられる他の方法を検討したか
イベント駆動にするか、定期実行にするか、とか
ドキュメント
設計書
設計書は存在するか
無いなら書く
詳細設計のみの設計書になっていないか
細かい粒度だけでなく、全体を理解できるようになってると助かる
機能全体で実現したい目的が書かれているか
機能全体のフロー図(シーケンス図)が書かれているか
機能全体の構成図は書かれているか
機能ごとの依存関係は明確になっているか
後続機能があるのと無いのとで対応は変わる
障害対応手順書
その手順書を不要にするためにアプリケーションを改修できないか
人間による対応は無くせるなら無くそう
最初に手順の流れを説明しているか
誰が対応できるかは明記されているか
特定の権限が無いとダメな場合があるため
前提条件が記載されているか
「どのサーバで」「何のツールが必要で」とか
緊急度、いつまでに対応が必要かは明記されているか
深夜のアラートが来た時とかに翌営業日対応で良いならそうしたい
後続バッチ等に影響がでるので、後続バッチが動き始めるまでに対応が必要なら、それを明記するべき
その手順は誰が実施しても同じように実施できるほどに曖昧さの無いものになっているか
実現するのはかなり難しいと思うけれど、可能な限りそうするべき
設計書へのリンクは貼られているか
参考資料としてあると良い
その手順書に従って実施して復旧できることを確認したか
実際流してみるとうまく行かないものなので、通しで確認は絶対必要
その手順書の作成者以外の誰かが手順書に従って実施して復旧できることを確認したか
手順書は運用者をスケールさせるために有用なので、手順書の作成者以外が実施できないと困る
その手順書にたどり着く導線は用意されているか
アラートメッセージに手順書へのリンクを張っておくのがオススメ
その手順書の存在をチームメンバーは認識しているか
手順書を作ったら周知しないと認識されない
手順書フォルダがあるならそこに放り込んでおく
その他
どの程度停止が許されるかは把握しているか
メンテナンスモードに入れる方法はあるか
以降は特定の処理系固有の観点
daemon系
常駐プロセス。基本的にプロセスは停止しない
適切な長さのスリープを挟んでいるか
常駐するタイプのやつは無限ループで処理することが多いけれど、スリープを入れてなかったら、処理データが無かった時などの処理が一瞬で終わってしまった場合に、短時間で何度も処理を発行して過負荷を与える場合がある
無限ループを使うときは必ずスリープを挟むべき
定期実行バッチ系
いわゆるcronバッチ。特定の時間に起動して処理が終了すると落ちる 依存する機能は存在するか
処理遅延が発生した時に何が起きるか把握しているか
処理遅延の結果、後続処理に追いつかれた場合に何がおきるか想定できているか
どの程度まで遅延が許されるかは把握しているか
手動、あるいは自動でリトライできるようになっているか
以上