信頼性の高いサービス運用のための5つの要素
さて少し遅れてしまったのですがSRE 2 Advent Calendar 2018の23日目です。
SREでどんな事をしているというより、どういうポリシーで信頼性を実現するか、という観点でまとめてみました。 SRE観点で運用改善をしていく! と言っても闇雲にやると「何やってるの?」になりがちなので。 まだ自分の中でもはっきりとしたものがある訳ではないのですが、やはり言語化してまとめ無いとフワフワしたままなので書いてみた感。 内容的に技術ポエムの方にしようかとも思ったのですが結局こちらに。
概要
サービスの運用にとって最も重要なことはサービスの信頼性を維持/向上させることです。 そのためには以下の5つの要素を意識した改善をし続けていくことが重要です。
- 回復性の設計
- Isolation
- トイルの撲滅
- 可視化
- モニタリング
サービスの信頼性を保つための5つの基本要素
高い回復性の実現
安定運用を実現するために最も重要なのは回復性(Realizability)の高いシステムの実現です。 回復性の高いシステムとは、障害が起こることを前提に素早く復旧しユーザに影響を見せないシステムをさします。 例えばリアルタイムシステムであれば100ms, バッチであれば数分でTake over/Re-runが実現できるのであればシステム障害の影響をユーザが感じることはありません。 最も顕著な例はHP NonStopnのプロセスペアです。アクティブ系が落ちても瞬時にスタンバイにテイクオーバーすることでシステム全体としての高い信頼性を実現しています。
システムが落ちないこはももちろん重要な指標ですが、MTTRを極小化して回復性の設計をアプリケーション、インフラ、及び運用手順により作り込むかがサービスの信頼性につながります。 理由の一つに技術の進歩のみならクラウド時代に突入しシステムが壊れる事が前提となっているためです。これはインフラの耐久性が落ちた訳ではなく大量のリソースを管理するため確率の問題です。 よってオンプレであっても同様の状態にあります。
Isolation
回復性を実現するためにはシステムごとのIsolationを高くする必要があります。障害の影響範囲が大きければ必然的に復旧時間が伸びる可能性が高いためです。 また、高いIsolationを持つシステムはポータビリティに優れシステムの部分的な入れ替えをしやすいためフレキシブルな運用も実現しやすくなります。 そのため、ミドルウェアやライブラリのバージョンアップをより低いリスクで実現する事ができるようになり、セキュアで効率的なシステムを保ち続ける事ができます。
これは仮想化のような集約基盤を使わないことを意味しません。 むしろ、仮想化特にDockerのようなコンテナ技術を積極的に利用する事でマシンからアプリケーションの独立ができ任意のマシンで動作可能なポータビリティを実現できます。
トイルの撲滅
高いIsolationを実現するとシステムが分散され複数のシステムを運用することとなり運用コストが増えてしまいます。 また、そうで無くてもサービスの成長と共にシステムは増え運用コストは増大していきます。 このような状態で高い回復性を持つシステムを構築するには、トイルを撲滅しシステムの数と運用コストの比例関係を無くすことが重要です。
トイルとは具体的には以下の状況を満たすものを言います。
- 手作業であること
- 繰り返されること
- 自動化できること
- 戦術出来であること
- 長期的な価値を持たないこと
- サービスの成長に対して比例的に増えること
これらはサービスが小さいうちは問題になりませんが、サービスが成長しシステムが増えていくにつれて多くの問題を引き起こします。リリース作業とか分析のための定期的なデータ抽出とかはといるの典型でしょう。
特に繰り返される手作業はスピード感を損ない回復性に致命的な影響を与えるのみならず障害の原因となります。大規模障害の多くはシステムの故障ではなくオペレーションミス
によって引き起こされることは珍しくありません。
トイルを撲滅するために自動化や運用プロセスの見直しを進めることでシステムの堅牢性を高めると共に運用負荷の比例的な上昇も削減することができます。
可視化の徹底
あらゆる改善は計測から始まります。可視化されてない状態では改善することはもちろん現状を把握することもできてないからです。 特にシステムの信頼性に直結するレイテンシやエラーは運用のKPIそのものであり、これらのメトリクスは必ず可視化されている必要があります。
また、上記のKPIを改善するためにトラフィックやシステムリソースの利用率などのメトリクスも可視化されている必要があります。 重要性を判断する観点でアプリケーションログから業務的なメトリクスを可視化することも必要です。そのためログは機械が読みやすいフォーマットで出すことが非常に重要です。 さらにほとんどのシステムはDB/ファイル連携またはRPCにより連携しているので、分散トレーシングやData Lineageも意識した可視化が重要になってきます。
適切なモニタリング
可視化は人間向けにメトリクスを表現するのが中心になりますが、モニタリングはシステムによるアクションを含んだ要素です。 何らかのメトリクスが閾値を越えるとされるアクションのことをさします。モニタリングは下記に分類できます。
- ページ(アラート): 即時対応が必要
- チケット: 業務時間または数日以内に対応が必要
- ロギング: 対応は不要。記録だけ残し性能分析や監査のために利用
これはITILのイベント管理におけるERROR/WARN/INFOと同様のものです。また、下位のイベントでも1分間に10回発生など閾値を超えた場合には上位のイベントとしてエスカレーションします。 特にページャー(オンコールの回数=アラート回数)は回復性に大きな影響を与えるのでKPIとして計測し、いかに削減していくかが重要になってきます。
適切なモニタリングとはまずイベントが上記の分類にしっかりとされているか否か、そしてそれが継続的にメンテナンスされているか(未知の問題から既知の問題になることでアラートからチケットに変わるのは本来は頻繁にある)が重要になります。
実現のための原則というかキーワード
本当はこれを原則集的なものにしたいのだけどそこまで体系化できてないので、とりあえず思ってることを単なに箇条書き。 多分アプリ観点としてはTwelve-Factor Appを守ってください、って感じかなー。
- アプリケーションにIPアドレスなど環境依存の値を入れさせない(DNSとかhostsとかで名前をつけるか環境変数)
- ログフォーマットやメトリクスを集めて後から分析する。人間のみやすさより機械の見易さ
- Infrastructure as a Codeを積極的に活用する
- ConfigurationはDB化し誰でもアクセス出来るようにする(担当者に聞かないとネットワークやサーバ設定が分からないを無くす)
- GUIよりCLI、手順書よりスクリプトを徹底する
- デプロイ単位が異なるものを同時にビルドしない
- SLAが異なるものを同じ場所(OSやJVM, コンテナなどリソース管理の単位)にデプロイしない
- ステートレスと冪等性を意識する
- 長時間動くバッチは悪である。並列化等で対処できないかを考える
- モジュールは小さく保ち起動速度を速くする
まとめ
実現のための手段は無限にありますし組織によって異なります。Dokcer化したり、モニタリングツール変えたり追加したり、マイクロサービス化してサーキットブレイカーを入れたりなどなど。 その作業を進める中でどういう効果があってそれをするかってのを今回記載したような観点で整理していけば説明しやすくなるんじゃ無いかなー、と。
それでは来年もHappy Hacking!