YAMAGUCHI::weblog

海水パンツとゴーグルで、巨万の富を築きました。カリブの怪物、フリーアルバイター瞳です。

SRE NEXT 2020で「サイト信頼性エンジニアリングの原則」というタイトルで登壇してきました #srenext

はじめに

こんにちは、Stackdriver担当者です。先週の土曜日に豊洲フロントで開催されたSRE NEXT 2020に登壇者として参加してきました。

sre-next.dev

どのセッションもすでにSREプラクティスを実践して試されているお話を聞けて、DevOpsの実践方法としてのSRE(Site Reliability Engineering)の広がりを感じられる素晴らしいカンファレンスだったと思います。

自分のセッションについて

sre-next.dev

自分のセッションは「サイト信頼性エンジニアリングの原則」というタイトルでの発表でした。資料は諸事情で一般公開できないのですが、主旨は概ね「SRE サイトリライアビリティエンジニアリング」(通称: SRE本)の書かれていることの抜粋とサマリーだったので、すでに実践されている方にとっては振り返りのような内容になってしまったかと思います。セッションスライド自体の公開を避けているのは、話した内容を伴わずにスライドに書かれている文言だけを切り取られると解釈によってはネガティブにも捉えられないなと思っていることによります。よって、このエントリーでお伝えしたかったことを再度簡単に触れていこうと思います。

なおSREに関するトピックをすべて触れていくとSRE本でもカバーしきれていないほどなので、これがすべてだとは決して思わないでいただきたいです。

単純性と一貫性

信頼性の担保とシステムの改善の両立のためには、変更はすばやく導入し、障害はすばやく戻すことが欠かせませんが、そのために単純性と一貫性が重要な役割を果たすという紹介をしました。

複雑性には必要な複雑性と不必要な複雑性が存在しますが、たとえば複雑性の例としてはpolyglotなマイクロサービスが挙げられるでしょう。プロジェクトにおけるプログラミング言語の選択というのは単にアプリケーションロジックだけではなく、それを実行するランタイムやそれをアプリケーションとしてバンドルするためのビルドシステム、依存するライブラリの更新など、実際にシステムにデプロイするまでに多くのツールやプロセスを必要とします。(以下エコシステムと呼ぶ)また採用やトレーニングといった人的なプロセスにも関わってきます。

プログラミング言語1つにつきそうしたエコシステムが伴うため、扱うプログラミング言語の数が増え扱うものが増えれば、管理にかかる負荷も増大します。プログラミング言語、設定管理方法や扱うOSの標準化を行うことで、SREが管理する技術範囲が限定され、かわりにより深い改善が行えるようになることでしょう。

どこまでを標準とするかは、導入する複雑さが得られるメリットほどの価値があるものかを検討する必要があると思います。すべてのユースケースではベストにならなかったとしても、1つを選ぶことで全体として管理が楽になることは間違いないでしょう。

モニタリングとアラート

モニタリングに関しては、1つの対象に対して異なる方法でのテストをおこなえるのであれば行ったほうが正確な状況を把握しやすい、という話をしました。よくある例はホワイトボックスモニタリングとブラックボックスモニタリングで、前者はシステムの内部情報の点検、後者は外形監視などが挙げられます。

モニタリングを行う理由はシステムの状態の把握と、障害の事前や事後のアクションを行うための通知(ページング、呼び出し)の設定などですが、ページングの設定を行う際の思いやりのなさにより、結果呼び出される側が疲弊することがあります。たとえば次のような場合はページングではなく、より緩い対応で済むはずです。

  • 冗長構成でクラスタ or マシンが1台だけ落ちた
  • 非常に長時間をかけてディスク使用量が95%になった
  • 仮想マシンが基盤クラスターが原因で落ちた
  • 対応しようのない障害

上で「より緩い対応」と触れましたが、たとえばアラート機構にはページングも含めて次のようなものが挙げられます。

  • ページ(呼び出し): オンコール対応
  • チケット/バグ/ダッシュボード: 当直対応、割り込み
  • ログ: 原因調査
  • メール: 後述するが極力使わない

オンコール対応というのは「担当者が寝ていても叩き起こして対応してもらう」ようなレベルのものを指します。SREで重要なのは一部の数字ではなく、ユーザー体験にどれくらい悪影響を与えているかなので、たとえば上記の冗長構成でマシンが1つ落ちたような場合は、引き続きサービスがリクエストを捌けているなら、業務時間中に落ちたマシンの復旧とそ原因を究明すれば良い話なので、この場合はチケットに登録しておけば良いでしょう。

どのレベルでの対応にするか判断のためにも外部プローブ(外部からのDNSクエリやヘッドレスブラウザなどを使ってTTFBの計測など)などのデータをあわせて計測するのが良いでしょう。

で、アラート機構としてメールを推奨しない理由ですが、運用方法によっては解決できる点もありますが、次のような理由が挙げられます。

  • 対応の様子を追跡できない
  • 障害に対するオーナーが不明
  • SN比
  • 人間の警戒に依存

cronや様々なシステムで簡単に設定できるのでメール通知を設定しがちですが、メールは傍観者効果が発生しやすかったり、なまじ簡単に設定できるためにノイズが多すぎて無視されやすくなったりします。inboxが他の業務メールと共通なことも多々あるため、注意深くフィルターしたり携帯の通知の設定も適切に行われなければいけません。こうしたものを運用で改善するよりは、適切なツールを用いたほうが効率が良いでしょう。

モニタリングとアラートに関しては当日 @larufa1 さんがVoyage Groupでの体験を共有してくださっていました。

speakerdeck.com

自動化

SREはトイルをできる限りエンジニアリングで排除するという姿勢で行うものなので自動化は常につきまといます。

たとえば複数のホストに手動でSSHを行って設定しているような処理があれば

pssh -H HOST1 -H HOST2 -H HOST3 "
  apt-get upgrade &&
  /usr/local/bin/make-new-widget.sh &&
  [ -f /etc/widget.cfg ] && echo Success || echo FAIL "

という形で自動化の第一歩が進められます。さらに推し進めていくと例えばGCPなどでは

gcloud compute instances create foo1 \
    --metadata-from-file startup-script=mysite/install-puppet.sh

このような形でスクリプト内に必要な処理を埋め込むことで抽象化のレイヤーを上げていけます。プログラムを書くときと同様に抽象化のレイヤーが上がることでより多くの処理をプログラムに任せられます。

ステートフル vs ステートレス

ステートフルなサービスは名前のとおり「状態」を持つサービスのことですが、「状態」を非常に簡単に定義すると「再生成が難しい一意なデータ」と言えると思います。障害が起きた場合はその「再生成が難しい一意なデータ」を復旧させなければならなくなり、それに備えて専用のバックアップ/リストア機構、また専用のモニタリング機構、アーキテクチャが必要となります。

たとえばMySQLクラスターにおいて

  • マスター(読み書き可): 1台
  • レプリカ(読み込み専用): 複数台

という構成があった場合、マスターノードには専用のモニタリング機構やバックアップ機構が必要になるでしょう。これらははじめのほうで触れた複雑性の議論にも関わってきますが、ステートフルなサービスがシステム内に増えれば増えるほどこうした機構が増えるので、なるべくステートレスなものに置き換えていけるような設計が肝心です。

情報の信頼先

あるシステムの特定の情報を得るために複数の情報ソースがあることは珍しくありません。その場合何を正とするかで判断が変わってきます。時計が1つなら何時か即答できますが、時計が2つだとどちらか正しい時刻か判断できません。

なのでたとえばシステムの状態を把握したいときはなるべく1つの情報源に頼るようにし、それが本当に判断するための情報源として適切か、設計時に判断したいところです。たとえばプロダクションサーバーと退役したサーバーが同居している系から返されるトラフィックのHTTP 2xx系の割合を調べたいときは、一番上流のSLBの層で得られた情報で判断するのが正しいでしょう。

SLOとエラーバジェット

SREで真っ先に出てくるのがSLOとエラーバジェットの概念です。

SLOで可用性99.5%を設定し、それを達成した場合に、これは「100%を0.5%達成できなかった」とみなすのではなく、文字通り「99.5%の可用性を達成した」と同時に「0.5%分システム改善のための余裕がある」という状態であるとみなすことが肝心です。

この0.5%を使ってたとえば

を試せます。可用性の話で言えば、0.5%であれば1ヶ月間に3.6時間が確保できます。たとえばカナリアリリースを実施している場合、これまでそれが起因のダウンタイムがなかったのであれば、すべての変更を canary → stable を経てローンチするのではなく、変更内容の大小やフラグの重要度に応じてカナリアの期間を短くする、あるいはカナリアをスキップするといった選択も取れるかもれません。

3.6時間は与えられた猶予なので、現実としてSLOよりも高い可用性を実現できてしまったとしても、無為にSLOを厳しくしてしまうのではなく、エラーバジェットをより迅速あるいはより堅牢な仕組みの導入のために利用するのが健全でしょう。

逆に厳しいSLOを設定してしまうと、アジリティが確保できなくなる可能性が高くなります。また当然ながらコストも高くなります。(一般的に 9 が一つ増えるごとに倍以上のコストがかかると言われている。)逆に言えばSLO 100%は「動かしたが最後二度と止められない」ということですから、通常のサービス運用ではまず必要のない値です。ユーザーに与える影響を加味しながら、なるべく余裕が得られる値に設定にできるよう、設定値に関して継続的な振り返りが必要です。

補足ですが、SLOの設定やその運用に関しては @chaspy さんが当日話されていました。

speakerdeck.com

テストとロールバック

SREを行う上で「システムは必ず落ちるものだ」という考え方を持つことは多くの場面で姿勢を正しくしてくれます。その一環でたとえばテストやロールバックを正しく行うことでシステム障害からの復旧を迅速に行ったり、障害範囲を限定できます。

  • 漸進的なロールアウト
  • 変更導入後の検証
  • 準備済みのロールバック

たとえばカナリアリリースは漸進的なロールアウトの例で、一部のクラスタ、各クラスタの1台だけ、など、限られた場所にだけ変更を導入して影響範囲を限定してリアルなデータで検証を行えます。問題があれば事前定義されたrunbookを実行してロールバックします。エラーバジェットは有効に使わないといけないので、SLOに影響を与えそうなエラーを発見したらすぐにロールバックして、原因究明のためにエラーバジェットを消費しないようにします。

障害耐性

エラーバジェットの消費として一番もったいないのは障害の復旧作業にそれを充てることです。したがって極力障害が起きないような対策を 打つことでより有意義にエラーバジェットを利用できるようになり(=システムの前向きな改善に使え)ます。

たとえばあるサービスをプッシュしたら空の設定ファイルを作ってしまってしまって、それが原因でサービスの再起動後にサービスが落ちてしまったという障害があった場合に、どうやって障害耐性をつけたらよいでしょうか。

いくつかの改善策が考えられますが、たとえば

  • Gracefulな退役: 新しい設定が読み込めない場合は以前の設定を使い続ける
  • 差分による予防: 設定の差分が単純に20%以上ある場合、あるいは特定のフィールドに変更があった場合には特定の検証プロセスを通るまでプロダクションにプッシュしない

などが挙げられます。

ポストモーテム

SREのおいてポストモーテムは最も重要と言える文化かもしれません。先程も書いたとおり「システムは必ず落ちるもの」と想定し、問題があった場合には人間ではなく「プロセスと技術」に注目して、「プロセスと技術」で改善を行うために振り返りを行います。決して人間を非難しないことが重要です。

たとえば次のようなポストモーテムがあったとします。

  • 事象: グローバルDNS障害
  • 原因: エンジニアが named.conf をtypoして保存してした。それをグローバルにプッシュしてBINDを再起動した。
  • アクションアイテム: エンジニアが次からはもっと注意する。エンジニアはリスクが高い変更を金曜日には行わない。

ここで問題なのは、原因をエンジニアとしていることと、アクションアイテムを人間に依存していることです。また「もっと」のような具体性を伴わない表現がされていることも問題です。原因はtypoをしたエンジニアでなく、typoがある設定ファイルがテストもなしにグローバルに展開されてしまうような仕組みです。またアクションアイテムも、それをどうプロセスやエンジニアリングで解決するかが書いてありません。これは次のように書き直せるでしょう。

  • 事象: グローバルDNS障害
  • 原因: 不正な named.conf がテストなしにすべてのBINDホストにプッシュされた。
  • アクションアイテム
    • 予防(こうした障害の再発をポジティブに防ぐにはどうしたらいいか)
      • named.conf をデータベースから読み込む
      • プッシュと再起動をスクリプト化して、スクリプトに安全確認を組み込む
    • 検出(同様の障害を正確に検出するまでの時間を減らすにはどうすべきか)
      • 監視の頻度を改善する
      • 監視対象の変更
      • ページをより速く行う
    • 緩和(次回この種の障害が起きたときの深刻度や影響度の%を減らすにはどうしたらいいか)
      • リロードして、再起動しない
      • 1つのサーバー(カナリア)だけ他のサーバーよりも速くプッシュするようにスクリプトを変える
      • DNSの機能を分割する(例: 内部 vs 外部、権威 vs 再帰
    • 修正(次回障害が検出されたときにどうすればより速く回復できるか)
      • オンコールプレイブックに起こすべきアクションを追加する
      • すばやくロールバックできるように各ホストの直前の設定を保存しておく

おわりに

こうした内容をお話しましたが、すべてを一度に導入しなければいけないというわけではなく、また何かを行うことでSREという認定が受けられるとかそういうたぐいのものでないので、システムの信頼性を高めるためにこうしたベストプラクティスを少しずつ導入していくのが良いのではないかなと思いました。しかし、とはいえ1つ、これがなければSREではないというものを挙げるとすれば、それはシステムのユーザーに対して信頼性を維持し高めることに貢献しているかどうか、ではないでしょうか。当たり前ですが、そうでなければ Site Reliability Engineering とは呼べないと思います。

SREのプラクティスであるSLOの設定というのはそういう意味では非常に妥当だと考えています。営利企業がITシステムを活用したサービスを提供している場合、会社の成功には必ずユーザーの満足度というのが存在し、経営の中では収益に紐付いた指標(KPI)とその目標値を設定しています。その会社の収益を支えるものがITシステムなのであれば、それらのKPIはSLIと紐づきますし、KPIの目標値はSLOと紐づくはずです。

今回SRE NEXTでは多くの企業がすでにSLOベースの運用をされていて、それらの事例を知ることができ大変有意義だったと感じています。ぜひ次回が開催されることを願うとともに、今後ますますSREのプラクティスが普及し、発展していくことを願っています。

参照

landing.google.com

このサイトに原文ではありますが、”Site Reliability Engineering” と "The Site Reliability Workbook" が無償で公開されていますので、気になる方はぜひ読んでみてください。特に両者ともに気になるトピックだけ拾い読みするだけでも問題ないと思います。

また書籍以外にもSLOのワークショップなどのコンテンツがありますので、こちらもぜひ見てみてください。

なおご存知の通り、"Site Reliability Engineering" は日本語訳版が出ていますし、また "The Site Reliability Workbook" に関しても現在日本語訳版が発刊に向けて最終段階だと聞いております。