20年間のサイト信頼性エンジニアリングで得た教訓
(sre.google)- Google SREは、小規模なデータセンターとPythonスクリプトベースの運用から出発し、コンピューティング規模は1,000倍以上、ネットワーク規模は10,000倍以上へと拡大した環境で信頼性を高めてきた経験を整理している
- 障害対応では迅速な対処よりも緩和策の安全性が優先され、誤った復旧手順は障害を減らすどころか連鎖的な障害を拡大させる可能性がある
- YouTubeとGoogle Calendarの事例は、グローバル変更の影響を限定するカナリアリリース、即座に元へ戻せるBig Red Button、実際の経路を検証する統合テストの必要性を示している
- 2017年のOAuthトークン障害のように中核的な依存関係が崩れると、ユーザーだけでなく内部の対応体制も揺らぐため、バックアップのコミュニケーションチャネルとグレースフルデグラデーションが必要になる
- 頻繁なロールアウト、自動化された緩和、災害復旧訓練、ハードウェアの多様性は、複雑な分散システムでMTTRを短縮し単一障害点を避けるための実務原則である
Google SREが20年間で経験した規模の変化
- 20年前のGoogleは2つの小規模なデータセンターを運用しており、各データセンターには数千台のサーバーがあり、2本の2.4Gネットワークリンクがリング状に接続されていた
- 当時の運用は、
Assigner、Autoreplacer、BabysitterのようなPythonスクリプトと、個別サーバー名が入った設定ファイルに大きく依存していた - MDBという小規模なマシンデータベースが、個々のサーバー情報を整理し継続的に維持するために使われていた
- 現在ではコンピューティングパワーが1,000倍以上、ネットワークが10,000倍以上に拡大した一方で、サーバー1台あたりの運用労力は減少し、サービススタックの信頼性はさらに向上している
- 運用ツールは、スクリプトの寄せ集めからサービスのエコシステムへ、さらに基本的な信頼性を提供する統合プラットフォームへと進化した
YouTube障害から得られた対応原則
- 2016年、YouTubeは分散メモリキャッシュシステムのバグにより15分間のグローバル障害を経験し、動画配信機能が停止した
- 障害緩和策は、障害の深刻度に見合ったものでなければならない
- YouTube障害の最中に行われた危険な**負荷遮断(load-shedding)**手順は、障害を直せなかっただけでなく連鎖的な障害を生んだ
- 危険な緩和策は、最良の場合には障害を解決するが、最悪の場合には誤作動して障害時間を長引かせる可能性がある
- 標準手順を迂回しなければならない状況であっても、まず深刻度を観察・評価したうえで選択すべきである
- 復旧メカニズムは、実際の緊急事態の前に十分にテストされていなければならない
- 障害の最中に初めて危険な緩和手順を実行するのは、高層ビル火災からの避難中に初めてはしごを使ってみるようなものだ
- 復旧手順が必要な作業を本当に実行するのか、担当者がその実行方法を理解しているのかを事前に確認する必要がある
- テスト自体にも、その措置を実施する際のリスクを下げる効果がある
- すべての変更はカナリアリリースで影響範囲を制限すべきである
- キャッシュ設定の変更は、意図しない結果によってYouTubeのサービスを13分間大きく麻痺させた
- グローバル変更をカナリア戦略で段階的に展開していれば、全体へ影響が及ぶ前に障害を限定できたはずである
- 関連資料として、カナリア戦略の論文とSREcon発表動画がある
Calendar障害から学んだロールバックとテスト
- 危険な変更には、事前に定義されたBig Red Buttonが必要である
- Big Red Buttonは、望ましくない状態を生んだ原因を元に戻すための、単純で実行しやすい安全装置である
- あるエンジニアが、問題が広がる前にデスクトップコンピューターの電源を抜き、大規模障害をかろうじて回避した事例があった
- 主要なロールアウトを計画する際には、「自分のBig Red Buttonは何か?」を考えるべきであり、すべてのサービス依存関係に対して緊急時に実行できる装置が必要である
- 関連記事としてGeneric Mitigationsがある
- 単体テストだけでは不十分で、統合テストが必要である
- 単体テストは個々のコンポーネントが期待どおりに動作するかを確認するが、ランタイム環境や本番要件を完全に再現することはできない
- 統合テストは、ジョブやタスクがコールドスタートできるか、コンポーネント群が連携して意図したシステムを構築できるかを検証するために使われる
- Calendar障害では、テスト経路が実際の利用経路と異なっていたため、多くのテストがあっても変更が現実でどう振る舞うかを評価する助けにならなかった
2017年のOAuthトークン障害と運用継続性
- 2017年2月、利用できないOAuthトークンのために数百万人のユーザーがデバイスやサービスからログアウトされ、32,000台のOnHubおよびGoogle WiFiデバイスが工場出荷時リセットを実行した
- ログイン失敗によって手動のアカウント復旧リクエストは10倍に増加し、Googleが障害から完全復旧するまでに約12時間を要した
- 障害対応には、主要なコミュニケーションチャネルとは分離されたバックアップチャネルが必要である
- 当時、各チームはGoogle HangoutsとGoogle Meetで障害対応を管理できると期待していた
- しかし、3億5,000万人のユーザーがデバイスやサービスからログアウトされた状況でGoogleサービスに依存するのは適切ではなかった
- 依存関係が分離されたバックアップのコミュニケーションチャネルを準備し、テストしておく必要がある
- サービスは例外的な状況でも**グレースフルデグラデーション(graceful degradation)**の形で機能し続けるべきである
- 可用性を「完全に正常」か「完全に停止」かだけで分けるのでは不十分である
- 性能低下モードでも最小限の機能を維持すれば、より一貫したユーザー体験を提供できる
- 性能低下がユーザーに見えない場合もあり、サービスは例外的な状況でも動き続けるよう設計されるべきである
災害、自動化、ロールアウト、ハードウェア多様性
- 災害へのレジリエンスと復旧テストは、事業継続戦略の中核要素である
- レジリエンステストは、障害・遅延・中断の状況でもサービスやシステムが耐えられるかを検証する
- 復旧テストは、全面停止の後にサービスが正常状態へ戻れるかを確認する
- Weathering the Unexpectedのように、自然災害やサイバー攻撃といった極端な状況も想定すべきである
- チームがテーブルトップゲーム形式で「ネットワーク接続の一部が予期せず切断されたらどうなるか?」のようなシナリオを検討する活動も有用である
- 明確なシグナルがある障害に対しては、緩和の自動化がMTTR短縮の手段となる
- 2023年3月、複数のデータセンターで複数のネットワーク機器がほぼ同時に故障し、広範なパケットロスが発生した
- この6日間の障害の間、サービスの約**70%**が、ロケーション、サービス負荷、障害発生時のネットワーク設定に応じてさまざまなレベルの影響を受けた
- 影響を受けたサービスの割合: {p:70}
- 特定の障害が発生したことを示すシグナルが明確であれば、手動の緩和措置を自動で開始してMTTRを短縮できる
- ユーザー影響をまず回避し、その後で根本原因を分析したほうがよい場合もある
- ロールアウト間隔が長いほど、変更の安全性を判断しにくくなる
- 2022年3月、決済システム障害によって顧客の取引完了が妨げられ、Pokémon GOのコミュニティデイが延期された
- 原因は単一のデータベースフィールドの削除であり、コードからそのフィールド利用が削除されていたため、安全な変更に見えた
- しかし、システムの一部でロールアウト周期が遅かったため、ライブシステムではまだそのフィールドが使われていた
- 複雑なマルチコンポーネントシステムでは、長いロールアウト遅延が特定変更の安全性判断を非常に難しくする
- 適切なテストとともに頻繁なロールアウトを行えば、この種の予期しない障害を減らせる
- 単一のグローバルハードウェアバージョンは単一障害点になりうる
- 重要な機能を1モデルの機器だけに任せれば、運用や保守は単純になるかもしれない
- しかし、そのモデルに問題が起きれば、その重要機能はもはや実行できなくなる
- 2020年3月、未発見のゼロデイバグを抱えたネットワーク機器がトラフィックパターンの変化によって不具合を顕在化させ、同一モデル・同一バージョンがネットワーク全体で使われていたため、相当規模の地域障害が発生した
- 複数のネットワークバックボーンがあったため、高優先度トラフィックをまだ動作している代替経路へ送ることができ、全面障害は回避された
- 重要インフラに潜むバグは、一見無害な出来事が起きるまで表面化しないことがあり、インフラの多様性維持が問題性の高い障害と全面障害を分ける要因になりうる
1件のコメント
Hacker Newsのコメント
記事は素晴らしく、幅広く適用できるように見える。「これはGoogleでしか通用しない話だ」というような部分は特にない。
通信チャネル、予備チャネル、その予備チャネルのさらに予備が本当に重要。Netflixでは、障害時に使うシステムのベンダーを選ぶ際、それがAWS上にないかを常に確認していたし、redditでは普段使っていたIRCが使えない場合に備えて、オフィスのサーバーに予備のIRCを置いていた。
GoogleにもAWS上に予備IRCサーバーがあると聞いたことがあるが、それは単なる伝説かもしれない。要点は、自分たちのインフラからできるだけ独立した補助連絡チャネルを確保することだ。
そのチームはクリティカルパス上にあったので、私たちのシステムが原因で呼び出されたなら、Google MeetだけでなくGoogle.comも一緒に落ちていた可能性はまったく低くなかった。Gmailのせいでメールも使えず、Google Fiなので業務用携帯も使えず、自宅ISPもGoogle Fiber/Webpassだったため、さらに予備の層が必要だった。
そのためGoogleには実際に通信用の予備IRCサーバーがある。場所は言わないが、まさにその理由からGoogleインフラの外に明示的に置かれている。
「幅広く適用でき、Googleでしか通用しない話ではない」という点で、他ではほとんど見たことがないのは運用パニックルームだった。本番環境へつながる予備VPNを備えたセキュアな部屋のことだ。
ある日、本番SANの調子がおかしくなってオンプレミスのデータセンターが落ち、そこにAtlassianも巻き込まれて死んだ。JiraもConfluenceもなく、CI/CDもおそらくなく、整理された復旧手順書もなく、部族知だけが残った。
人々は激怒したし、それも当然だった。顧客向けシステムとインフラ関連システムを同じかごに入れるのは本当に危険だ。
少なくとも2年前、私がまだそこで働いていたときはそうだった。
いつか完全なコールドスタート問題の解法を聞いてみたい。巨大な自社スタックを持つ企業には、基盤インフラに循環依存がある。
ソフトウェア定義ネットワーキングでは、パケットルーティングを再開するには何らかのソフトウェアが起動している必要があり、ディスクレスマシンには起動用のストレージが必要で、認証サービスはセキュリティ権限付与をブートストラップするためにストレージアクセスが必要になる。
今は複数の独立リージョンを運用し、完全に電源が落ちたデータセンターを既存インフラからブートストラップする形で対処している。しかし、スタック全体を完全な電源断状態から再び立ち上げたという話は聞いたことがない。
数年前にFacebookが運用ネットワークを完全に壊したときでさえ、マシンの電源は入っており、内部接続性も一部残っていた。大規模な太陽嵐のような出来事で電力網が世界的に長期間ダウンし、発電機まで使い果たした場合、AWSやGCPのようなクラウドが必ず復活する保証はない。
おそらく、優れた予備電源と、電力網のサージから完全に隔離できる能力を備えた小規模な専用データセンターがあるのだろう。
スタック上位では、ライブラリ作者がこっそり追加した依存関係を追跡するのに役立ち、下位では、土台にあるべきものが本当に土台にあることを保証する助けになった。
文書化された手順が古びないように仮想自動クラスタの起動・停止も行っており、SREとしていた6年間で、その手順が90日から1時間未満に短縮されるのを見た。
物理オブジェクトが必要なグローバル暗号鍵管理のようなものも、ゼロから再起動する訓練を定期的に行っていたし、年次のDiRT訓練では、どの個人・チーム・オフィスもシステムの継続運用に不可欠な条件にならないよう確認しようとしていた。
遅く始めると非常に苦痛だが、最初からそうしていればすぐ慣れ、破壊的変更や奇妙な依存関係を早期に見つけられる。
ハードウェアにも適用できる。何かが抜かれたり初期化されたりする状況に耐えられるよう、アーキテクチャが変わる。より多くの自動化、バージョン管理、変更管理が必要になり、そのおかげで障害予防や迅速な復旧だけでなく、作業全体も速く単純になる。大きな文化的変化だ。
記憶では、アプローチの一部は機密情報と見なされていたので、これ以上詳しくは話さない。
どの電力網がコールドスタートを最も多く経験してきたのかも興味深い。理想的には、そうした場所はすでにうまくやれるはずだ。カリブ海かアフリカのどこかだろう。
ただし、小規模な電力網のコールドスタート、たとえばディーゼル発電機1台と太陽光がある離島のようなものは簡単すぎて、良いケーススタディにはならないかもしれない。
インターネット自体は、交流電力網のようにはコールドスタートできないことは明らかだ。ASが多すぎる。ASが何を意味するか少し考えれば、調整されリハーサルされたコールドスタートがなぜ不可能なのかわかる。
このテーマについてさらに深く知るには、Google の Building Secure and Reliable Systems をほぼ読み終えたところですが、軽い読み物ではなく、きちんとした教科書に近いものです。
かなり興味深い本で、多くの内容は常識のように見えますが、「常識」という言葉自体が矛盾しているという表現もあるように、知識全体を一度にリフレッシュするのに役立ちました。
最近、いくつかの会社が SRE 組織を畳み、メンバーを SWE チームへ移したという話を聞きました。LinkedIn、Adobe、Robinhood がそうしたという噂があります。
それで、SRE は簡単に資金が集まっていたバブル経済の副産物なのかと考えるようになりました。大きなコストをかけて SRE チームを別に置かずに運用することはできないのでしょうか。
システム管理者や QA テスターがほとんど姿を消し、多くの機能がソフトウェア開発チームへ移っていったように、10年後にも SRE が残っているのか気になります。
しかし今はレイオフが続く状況なので、その点を気にする会社は多くありません。開発者の専門領域でなくても問題に投入する流れは消えない業界トレンドで、不況期にはさらに目立つでしょう。
フルスタック開発者は、2つの役割を合わせても報酬は2倍にしない好例です。
ただし、残りの論旨は依然として正しいと思います。最近は DevOps によって開発者に求められる能力の幅が広がり、SRE とかなり重なっています。企業は SRE チームを縮小し、責任を開発者へ分散させる可能性が高いでしょう。
もう1つの大きな理由は自動化です。リンク先のサイトを長く読んでいると、Google 初期には SRE がグラフを手動で見ながらデプロイするなど、手作業を多くしていたことが分かります。
当時は Google でさえシステムの自動化が十分ではなかったため、SRE が必須でした。Sisyphus の話 https://www.usenix.org/sites/default/files/conference/protec... を見ると、Google が標準化された自動化を最初に導入することに失敗したことで、SRE の雇用安定性がどのように保証されたのか、ある程度理解できます。
自分が書いたソフトウェアの運用を他人に渡すのは論理的ではありません。SWE をオンコールに入れればよいのです。手作業が最善だと思うなら自分でやらせるべきで、その程度ならひどいエンジニアとして解雇すべきです。
面接はあれほど厳しく行うのに、いざ自分がプログラミングしているコンピュータがどう動作しているのか知らないというのは奇妙です。OS の動作などは学部課程にもある内容なのに、それを主に独学してきたシステム管理者出身者が多い職務や肩書きへ押し付けるのも奇妙です。
私が知っている優秀な SWE は皆、OS、コンピュータ、ネットワークがどのように動くのかを知っていました。
SRE が今やっている一般的な自動化、開発ツールの提供、開発者体験の改善といった仕事は、プラットフォームチームへ移りつつあります。今後、役割は大きく変わると思います。
1つの SRE チームが複数の開発チームを支援できますし、開発チームは複雑なインフラや分散システムの側面にほとんど時間を使わないことが多いです。日常的に気にしている領域ではないからです。
だから、専門の開発チームとは別の単位で動くインフラ組織があるのは妥当です。それを SRE と呼ぶにせよ、SRE SWE チームと呼ぶにせよ、単にインフラと呼ぶにせよ、一定以上の規模ではチーム横断の関心事が増え、そう分離したほうが安くなります。
専任の SRE を置くと、運用や関連システム、ツール、アラートなどについて本当の専門家がいて、結果に対する明確な責任も生まれます。しかし彼らは自分たちが保守するシステム自体を完全に所有しているわけではないため、組織上の問題が起こり得ます。
「私たちは X をリリースしたいのに SRE が反対している」といったことや、その逆が起こり、SRE でない人たちがサポートしづらいコードの責任を負わなくなる可能性もあります。
逆に SRE のいないエンジニアリングチームは、そうした組織的・社会的問題を減らせますが、運用の信頼性は多くの優先事項の1つになります。
実際には、多くの企業がビジネス成果として信頼性をそれほど重視しないことを選びつつあるのだと思います。特に機能開発の機会費用が大きくなると、なおさらです。
自動緩和については、本当に長く考える必要があります。30年のキャリアの中で、自動緩和が問題をさらに悪化させるのを何度も見てきました。だから自己修復が本当に必要なのか、慎重に検討すべきです
2014年に社内向けのモバイルクラッシュ報告ソリューションを作りましたが、バックエンドの一部は Redis を単一障害点とする1台のサーバーで動いていました。フェイルオーバー手順は半自動で、人がアラートが有効かを確認してから開始する必要がありました
落ちても実際の金銭的損失はなく、最悪でもモバイルアプリ開発者がしばらく不便になるだけでした。10年間運用して、フェイルオーバーが必要になったのは片手の指2本で数えられる程度でした
SLA のないシステムだったにもかかわらず、はるかに重要な社内システムより稼働時間は良好でした
逆に GitHub の事例を見ればよいです: https://github.blog/2023-05-16-addressing-githubs-recent-ava..., https://github.blog/2018-10-30-oct21-post-incident-analysis/, https://www.datacenterknowledge.com/archives/2012/12/27/gith...
もちろん GitHub ははるかに大きな規模で運用しています。要点は、冗長化と自動緩和は複雑性を増し、定義上ほとんどテストされていない状態で、予測できない状況の中で動作するということです
だから SLA と障害コストを考え、障害を防ぐために追加する複雑性とのバランスを取る必要があります。1998年ごろ、NetApp 2台を高可用性構成で組んだのですが、1台が故障した際にもう1台の全ディスクまで壊してしまったことが、私の最初の教訓でした
同じころ Cisco PIX ファイアウォール2台でも同じことがあり、それ以来、高可用性と自動フェイルオーバー・緩和には常に慎重になっています
実務で ビッグレッドボタン と意図的な段階的性能低下をどう扱っているのか気になります。特に、システムが問題を抱えている最中でも、それらが動作することをどう保証しているのかが気になります
たとえばデータベースベースのフィーチャーフラグを使うのか、そうだとすればデータベース自体やアクセス API が過負荷のときはどうするのか気になります
あるいは環境変数のような静的な起動フラグを使うのか、その場合に十分速くデプロイされることをどう保証するのかも気になります。あるいはまったく別の方法があるのかも気になります
重要経路の一部で冗長化を使わなくても、システムがすべての保守担当者の頭に収まるほど単純で、簡単に再起動したりロールバックしたりできるなら、その方が良い場合があります
しかし会社が「ファイブナインの稼働時間」のような保証をし始めると、その保証を維持しながら開発と改善を続けられるシステムを設計するために、ある程度の複雑性は必要になります
Google では、特定のクラスタが健全でないと判断されると日常的に「バックエンドのドレイン」を行っており、API/ロードバランサ層でそれを素早く処理するシステムがありました
他の場所では、アプリケーションレベルのフラグで処理しているのも見たことがあります。
kubectl editをするような形で、明らかに理想的ではありませんが、動きはしました第一に、単純に保つことです。凝ったロジックや複雑なデータストアなしに、フラグを簡単に確認する程度がよいです
第二に、できるだけソースに近いところに置くべきですが、クライアントを過信してはいけません。古いバージョン、伝播遅延、バグがあり得るため、クライアントとサーバーの両方で劣化モードを選べるのが望ましく、どちらか一方だけならサーバー側の方がましです
第三に、実トラフィックで頻繁にテスト することです。テスト環境を信じず、0.1% のような小規模な定期テストと、予定された大規模テストを行うべきです。テストしていなければ必要なときに動かず、1年前に動いたなら今は動かない可能性が高いです。テストされていない装置は、解決より被害を大きくすることがあります
たとえば Hacker News に、コメントの横にプロフィール写真を表示する新機能を追加したとしましょう。当然すべてをマイクロサービスにしたので、フロントエンドのページ生成器がプロフィールサービスに呼び出しを送り、プロフィールサービスが照会したうえで画像の場所を返す構成だと仮定します
リリース計画の一部として、新しいコンポーネントがプロフィールサービスや画像ストレージを過負荷にした場合に従う ビッグレッドボタン手順 を文書化します。つまりネットワーク層で自分のサービスの外部リクエストレートを制限するコマンドを実行し、緊急時にはおそらく 0 にします
照会は失敗しますが、ページ生成器はプロフィール写真なしでコメント本文をレンダリングし続けるよう、段階的に劣化する設計になっています
これは実際の設計文書でも、何をどう作れという助言でもなく、単に要点を説明するためのクレヨン画にすぎません
djb の CDB(constant database)でもやりましたし、JSON 設定ファイルを API でポーリングしたり、dbm/gdbm/Berkeleydb/leveldb を使ったりするケースも見ました
この方式は他のビッグレッドボタンにも拡張できます。優雅ではありませんが、ヘルスチェックを提供するかを決めるためにファイルの存在有無を確認するサービスを何度も運用しました。ロードバランサのローテーションからノードを外すことは、ファイルを1つ作るのと同じくらい簡単でした
肝心なのは、データベース障害が起きたら、システムが 最後に確認された正常な設定 をデフォルトとして使うようにすることです
「復旧メカニズムは非常時の前に完全にテストされていなければならない」という文を本当に強調したいです。Google で思いがけず SRE になり、二重否定 を誤用して全社的に知られるようになった者として、これは最初から正しくやるべき非常に重要なことです
気になる Googler は、社内で私のユーザー名を検索してみれば、測定できないほど大きな影響をどう生み出したのか見つけられるはずです
障害を防ぐ最も安上がりな方法は、ライフサイクルの早い段階で捕まえること。ソフトウェアのバグは本物の虫に似ている。最初は卵、つまり変更のアイデアであり、孵化した幼虫が最初の POC だ。運用環境に到達する頃には成虫になっている
成虫になる前の段階があるのでは? その通り。アプリケーションは成熟する前に複数の段階を経る必要がある。バグが育ちきって卵を産む前に見つけるほうが、はるかに安く済む
カナリアリリースが難しく、ロールバックにも問題があるなら、運用リリース前のテストを増やすべきだ。リンター、単体テスト、エンドツーエンドテスト、プロファイラー、合成モニター、読み取り専用の本番レプリカ、性能テストなど、可能な限り多くの方法でバグを早期に見つけるべきだ
フィーチャーフラグや後方互換性なども有用だが、Shift Left には勝てない
FinTech、銀行、ヘッジファンド、暗号資産分野で 15 年間 SRE を務めた視点による似たようなリストに興味があるなら、この記事をおすすめする: https://x.com/alexpotato/status/1432302823383998471?s=20
例: 「25. フィルター条件で既存ルールを探すより新しいルールを作るほうが簡単な ルールエンジン があると、最終的には重複ルールが大量に生まれる」
「障害を起こしかけた変更を提出したエンジニアが、変更が伝播する前にデスクトップコンピューターの電源を抜いて、大規模障害をかろうじて回避した」というのは、いったいどういう意味なのか?
その結果、インフラの SWE たちは実際のボタンを作らず、一日中ばかげた CLI を書くことになった。私が辞める頃にはかなり変わりつつあったが
Google は社内障害をもっと公開すべきだと思う。この障害は特に社内で非常に有名だった
とてつもない規模でも、シェルツールや RPC クライアント CLI は世界中のあらゆるマシンにかなり素早く接触できる
pssh風のユーティリティで回した記憶がある10 年前のことなので今もそう使っているかは分からないが、その方式は驚くほど速かった。そういう類いのことだったのかもしれない
しかし 20 年前ならもっと一般的だっただろうし、今でも小規模な組織ではまだあり得る