GitHubで8月17日に発生した大規模障害について、同社が原因の説明を公開しました。引き金になったのはコードや設定の変更ではなく、過去最高を更新したトラフィックにインフラの一部が追随できなかったことです。復旧を長引かせたのは、失敗したリクエストを機械的に投げ直すリトライの連鎖でした。
止まっていたのは7時間47分
障害は日本時間8月17日22時28分から18日6時15分まで、7時間47分にわたって続きました。影響を受けたのはIssues、プルリクエスト、API、Actions、そしてCopilotです。ピーク時のエラー率は、WebとAPIのトラフィックで約20パーセント、アーカイブとリポジトリの生コンテンツのダウンロードでは約50パーセントに達しています。
認証まわりの傷も深く、SAMLとOIDCによる認証、SCIM、Team Syncが軒並み影響を受けました。データレジデンシー環境のGitHub Enterprise Cloudでは、GitHub.com側に置かれた公開ワークフローのステップ定義に依存するActionsのワークフローが動かなくなっています。
復旧は段階的でした。大半のサービスは中部米国のデータセンターの回復にあわせて日本時間18日1時36分ごろに戻り、Actionsは3時3分ごろまで不安定なまま、Copilotのトークン発行サービスが完全に戻ったのは6時2分でした。
発端はサイドカーのオートスケール設定
直接の原因は、中部米国のロードバランサーで起きたネットワークの飽和です。そこにたどり着くまでの経路が、今回の説明でいちばん技術的に面白い部分でした。
出発点は、サービスメッシュのIstioが各サービスに寄り添わせているサイドカーのPodです。これが同時実行数の上限に達したにもかかわらず、自動的に増えませんでした。スケーリングのポリシーがホスト側のサービスの指標だけを監視しており、サイドカー自身の上限を見ていなかったためです。監視していない場所が先に詰まれば、オートスケールは何も起きていないと判断します。
1つの詰まりは次の詰まりを呼びました。最終的に4台のHAProxyノードがフローの上限を使い切り、ゲートウェイの認証経路が劣化して、広い範囲で認証の遅延と失敗が起きます。ここに、失敗したら投げ直すという楽観的なリトライの実装が重なり、内部のロードバランサーがさらに押しつぶされました。対処として該当ノードのHAProxyを同時に一時停止したところ、広範囲が即座に回復したと説明されています。
トラフィックが10倍に膨らんだリトライの嵐
失敗しつつあったトラフィックの一部は、中部米国からノーザンバージニアへ移されました。ところが移した先で別の問題が顔を出します。ある内部エンドポイントの応答が遅れたことで、VS Codeに潜んでいたリトライの不具合が誘発され、トラフィックが約10倍に膨らんだのです。
数字で見ると影響の大きさが分かります。Copilotのトークン発行サービスの負荷は、通常なら毎秒7,000から9,000リクエストのところ、毎秒70,000から100,000リクエストまで跳ね上がりました。失敗した1件のトークン処理が追加の要求を大量に生み、そのままリトライのループに入ってしまう構図です。
収拾には2段構えの手当てが必要でした。まずゲートウェイのリトライ処理を一時的に弱めるプルリクエストを当て、次にロードバランサーの手前でトークン要求に403を返して遮断し、そのうえでサイトごとに少しずつ流量を戻していきます。復旧作業の最中に、codeloadエンドポイントに対するスクレイピング攻撃が重なったことも、事態をややこしくしました。
4月から月間コミットが倍増していた
GitHubは今回の障害と、8月6日に起きたActionsの障害のどちらについても、コードや構成の変更が原因ではなく、本質はいずれも容量不足だったと認めています。需要が容量を超える前に重要なコンポーネントを増強できなかった、という言い方です。
背景にあるのは負荷の伸びです。同社によれば、4月以降で月間のコミット数は14億から29億へと倍以上に増えました。これに対して、300万を超えるCPUコアと120ペタバイトの高速ストレージ、それに相応のネットワーク容量をすでに追加しています。既存のデータセンターには電力が許す限りのハードウェアを詰め込み、あわせてAzureへの移行を加速させました。
その結果、Azureが処理しているのはプラットフォーム全体の負荷の約58パーセント、Git操作では半分に達しています。5月時点でプラットフォーム負荷の12パーセントだったことを考えると、移行のペースはかなり速いと言えます。次の目標は、読み取りの処理能力が読み手の数に対して線形に伸びるアーキテクチャで、規模の大きなモノレポから順に展開する計画です。
再発防止策と、残っている宿題
公開された再発防止策は、今回詰まった箇所を素直になぞる内容になっています。サイドカーの同時実行数と容量を考慮したオートスケールポリシーへの修正、影響を受けたサービス全体でのIstioのリクエスト数や同時実行数、スケーリング上限の監査、ゲートウェイとクライアント双方でのリトライ上限とバックオフの見直し、Copilotのトークン要求を増幅させたVS Code側の挙動への対応、そしてロードバランサーの容量監視とリージョン間フェイルオーバーの強化です。
これに加えて、サービス間の呼び出しにリトライ回数の上限とリトライ予算、可変のタイムアウトを一貫して適用する方針が示されました。リトライの嵐と負荷の連鎖を止めるための共通のブレーキと考えると分かりやすいでしょう。もう1つは、優先度を低く設定していたCPUとメモリのアラートの棚卸しで、急なトラフィックの跳ね上がりで壊れうる部品を洗い出す狙いです。
同社のCTOであるVlad Fedorov氏は、規模の問題だけが課題ではないとも書いています。変更の速度と複雑さが増したのに対して運用の実務が追いつかなかったとして、テストの強化、より安全な展開、可観測性の向上、実効性のあるアラートに人と資源を振り向けたものの、この作業はまだ終わっていないと述べています。重要なシステムを互いに切り離し、共有している依存関係を減らす作業も並行して進めているとのことです。
まとめ
8月17日のGitHubの障害は7時間47分に及び、Issuesやプルリクエスト、API、Actions、Copilotが影響を受けました。原因はコードや設定の変更ではなく、Istioのサイドカーのオートスケールが効かなかったことに始まる容量不足で、HAProxyの飽和と認証の劣化へ連鎖しています。復旧の遅れはVS Code側のリトライ不具合による約10倍のトラフィック増幅が主因でした。背景には月間コミットが4月の14億から29億へ倍増した負荷の伸びがあり、GitHubはCPUコアやストレージの増設とAzureへの移行、リトライ制御の統一で立て直しを図る構えです。
