Google Cloud 2025年 空の項目で落ちた Service Control

攻撃ではない。API の要求ごとに割当と方針を確かめる Service Control に、旗で守られず誤りの処理も無いコードの道が2週間眠っていた。空の項目を含む方針が書き込まれ、数秒で全地域に複製され、全地域の Service Control が同時に落ちた。止める所は、新しい道を旗で閉じておくこと、読む時に確かめること、データを地域ごとに少しずつ広げること、戻る時に一斉に押し寄せないことにある。

Google Cloud、Google Workspace、Google Security Operations の外向きの API の要求で 503 の誤りが増えた[1]。障害は米国太平洋夏時間の2025年6月12日10時49分に始まった[2]。状況の頁は、全部の製品の回復を同日18時18分とした[3]。Google は6月13日の報告で、Service Control の変更と手作業の方針の配信を止め、再発を防ぐ7つの手当てを挙げた[1]。手当ての完了は、2026年11月時点で公表されていない。2026年11月時点の公開資料で書いています。

要点

  • 2025年5月29日、割当の方針を追加で確かめる機能が Service Control に入った。地域ごとに展開したが、落ちた道は方針の変更が無いと通らないため、展開の間に一度も動かなかった[1]。
  • その変更には適切な誤りの処理が無く、機能の旗で守られてもいなかった。Google は、旗で守っていれば試験の環境で見つかったと書く[1]。
  • 6月12日、意図しない空の項目を含む方針が書き込まれ、数秒で全世界に複製された。各地域の Service Control が NULL ポインタを参照し、再起動を繰り返した[1]。
  • 止める赤いボタンは用意されており、40分以内に展開を終えた。それでも us-central1 では、再起動したタスクが一斉に方針の表へ押し寄せ、回復に最大で約2時間40分かかった[1]。
  • 状況の頁も同じ障害で落ち、最初の報告が出たのは約1時間後だった[1]。

何が起きたか

5月29日の機能の展開、6月12日の方針の書き込み、全地域での異常終了、40分での赤いボタンと us-central1 の長い回復の4つの段 1 機能を出す 2025年5月29日 地域ごとに展開 新しい道は通らず 2 方針を書く 6月12日10時45分頃 空の項目を含む 数秒で全世界へ 3 全地域で落ちる 10時49分から NULL の参照で 再起動の繰り返し 4 戻る 40分で赤いボタン us-central1 は 最大約2時間40分 時刻は米国太平洋夏時間。1から2まで14日、2から3まで数分 始まりと気付きは同じ日。2分以内に担当が調べ始めた
図1 眠っていたコードの道が踏まれるまでと、戻るまで
日時 米国太平洋夏時間出来事
2025年5月29日割当の方針を追加で確かめる機能を Service Control に足す。コードと実行形式は地域ごとに展開したが、落ちた道は方針の変更が無いと通らず、展開の間に動かなかった。止めるための赤いボタンは付いていたが、誤りの処理と機能の旗は無かった[1]
2025年6月12日 10時45分頃Service Control が読む地域の Spanner の表に、方針の変更が書き込まれる。数秒で全世界に複製される。中身には意図しない空の項目があった[1]
同日 10時49分障害が始まる[2]。各地域の Service Control が空の項目を読んで NULL ポインタを参照し、再起動を繰り返す[1]。状況の頁は始まりを10時51分と書く[3]
始まりから2分以内SRE の担当が調べ始める[1]
10分以内根本の原因を突き止め、その道を止める赤いボタンの準備に入る[1]
約25分赤いボタンを出せる状態になる[1]
40分以内赤いボタンの展開を終え、小さい地域から回復が始まる[1]
約1時間後最初の障害の報告を状況の頁に出す。状況の頁の基盤もこの障害で落ちていた[1]
12時48分us-central1 を除く全地域で緩和する[2]
13時49分障害の終わり。続く時間は3時間[2]。us-central1 では、タスクを作る速さを絞り、通信を複数の地域のデータベースへ振って負荷を下げ、最大で約2時間40分かかった[1]
18時18分最後まで残った Vertex AI のオンライン予測が回復し、全部の製品が回復する[3]
6月13日 16時45分Google が障害の報告を出す[1]
  • 影響は、利用者から見て API と画面への接続が途切れ途切れになることだった。すでに動いている流し込みの処理と IaaS の資源には影響が無かった[2]。
  • 影響を受けた製品の一覧には、IAM、Cloud Storage、BigQuery、Compute Engine などのほか、Gmail、Google Drive、Google Meet などの Workspace の製品が並ぶ[2]。利用者の数や損害の額は、Google の報告には無い。

起きた仕組み

空の項目を含む方針が地域の表に書かれ、数秒で全地域に複製され、全地域の Service Control が同じ道で落ち、外からの API の要求に503を返した 方針の変更 意図しない空の項目 10時45分頃 地域の Spanner の表 割当と方針を持つ ほぼ即時に複製 全地域の表 数秒で同じ中身 段階も待ちも無い 各地域の Service Control。地域ごとに独立して置かれていた 地域 1 割当の確かめで NULL を参照 地域 2 割当の確かめで NULL を参照 地域 3 ほか 割当の確かめで NULL を参照 外からの API の要求に 503
図2 地域に分けた実行形式が、世界で1つのデータで同時に落ちた
段何があったか
役割Google と Google Cloud の API の要求は、地域に分けた管理と制御の面を通る。そこで要求ごとに認可、方針、割当のような確かめをする。中心の実行形式が Service Control で、地域ごとに置かれ、地域のデータの置き場から割当と方針を読む[1]。
コード5月29日に足した割当の確かめの道は、方針の変更が無いと通らない。地域ごとの展開では一度も動かなかった。この道には適切な誤りの処理が無く、機能の旗で守られていなかった[1]。
データ割当の管理は世界で共通のため、方針のデータはほぼ即時に全世界へ複製される。6月12日の変更は数秒で全地域に届いた[1]。
実行各地域の Service Control が、それぞれの地域の表から空の項目を読み、NULL ポインタの参照で落ち、再起動を繰り返した。地域ごとに置いていたことが、そのまま全地域で同じことが起きる理由になった[1]。
戻り赤いボタンで道を止めたあと、大きな地域ではタスクが一斉に再起動し、頼る基盤の Spanner の表に押し寄せて過負荷にした。Service Control には、ゆらぎを入れた指数的な待ちが無かった[1]。
速報と報告で原因の書き方が違う

6月12日の速報は、原因を API の管理の仕組みへの無効な自動の割当の更新と書いた[2]。翌日の報告は、方針の変更が表に書き込まれ、その中の空の項目が旗の無いコードの道を通らせたと書く[1]。以下は後の報告による。誰が、どの仕組みで方針を書いたかは、どちらにも書かれていない。また、地域に分けた作りは、全地域が同じデータを読む限り、データの誤りに対しては分けたことにならない。

戻りを長くしたもの

赤いボタンの後に多数のタスクが同時に再起動して方針の表に押し寄せ、作る速さを絞り複数地域のデータベースへ振って負荷を下げた タスク 再起動 タスク 再起動 タスク 再起動 多数が同時に 方針の表 過負荷 取った手 タスクを作る速さを絞る 複数地域のDBへ振る 最大約2時間40分 us-central1 のような大きな地域で起きた。小さい地域は先に戻った
図3 戻る時の押し寄せ

落ちた原因を止めても、止まっていた側が一斉に戻ると、頼る先が次に落ちる。Google の SRE の本は、再試行の予定には必ずゆらぎを入れた指数的な待ちを使うよう求め、再試行が同じ時に重なると自ら増幅すると書く[4]。この件の Service Control には、それが無かった[1]。

どこで止められたか

コードの展開、データを読む所、データの広げ方、失敗の倒し方、戻り方、知らせ方の6つの段に止める所を置く コードの展開 データを読む所 データの広げ方 失敗の倒し方 戻り方 知らせ方 1 新しい道を旗で閉じて出す 既定は無効。社内の計画から地域ごとに開く 2 読む時に形を確かめる 空の項目は拒み、その方針だけを使わない 3 データも少しずつ広げる 全地域へ数秒で届く道に、待ちと確かめを置く 4 確かめごとに倒す向きを決める 割当は通す側、認可は拒む側 5 ゆらぎを入れて戻る 再起動と再試行が同じ時に重ならない 6 知らせる道を別に持つ 状況の頁と監視を、落ちる側に頼らせない
図4 段ごとの止める所
止める所この件でGoogle の手当て
新しい道を旗で閉じて出す旗が無く、展開の段階は実行形式にだけ掛かっていた。新しい道は方針の変更が来るまで動かず、段階の間に試されなかった[1]大事な実行形式への変更は、すべて機能の旗で守り、既定で無効にする[1]
読む時に形を確かめる空の項目を読んで NULL ポインタを参照した[1]静的な解析と試験を改め、誤りを正しく扱い、要るなら通す側に倒す[1]
データも少しずつ広げる方針のデータは数秒で全世界に複製された[1]世界で複製するデータを使う全部の仕組みを監査し、確かめと検知の時間を取りながら少しずつ広げる[1]
確かめごとに倒す向きを決める1つの確かめの失敗で、Service Control 全体が要求を返せなくなった[1]Service Control を部品に分け、機能を切り離して通す側に倒す。確かめが失敗しても API の要求を返せるようにする[1]
ゆらぎを入れて戻るus-central1 で再起動が表に押し寄せた[1]全部の仕組みが、ゆらぎを入れた指数的な待ちを使うよう監査する[1]
知らせる道を別に持つ状況の頁の基盤が落ち、最初の報告まで約1時間かかった。Google Cloud の上で監視を動かしていた顧客は、障害の合図そのものを失った[1]Google Cloud と主な監視の製品が落ちても、監視と連絡の基盤が動くようにする[1]

1か2があれば、空の項目は異常終了につながらなかった。3があれば、1と2が抜けても、最初の地域で気付いて止める機会があった。4から6は、起きた後の幅と長さを決める。赤いボタンは用意されていたが、効いたのは落ちた後だった[1]。

守り方

根本の直し方
  • 新しいコードの道は、機能の旗で閉じたまま出し、既定で無効にする。開く時は社内の計画から、地域ごと、計画ごとに広げる。Google は、旗で守っていれば試験の環境で見つかったと書く[1]。
  • 実行形式の段階的な展開は、その道が実際に動いたことまでは確かめない。新しい道を動かす入力を、段階の中で意図して流す。
  • 外から読むデータは、読む時に形を確かめ、外れた1件を捨てて残りで動く。ほかの仕組みが書いたデータも、利用者の入力と同じに扱う。
  • 世界で共通のデータも、地域ごとに段階を踏んで広げ、各段で異常が無いことを見てから次へ進む。データは即時に届くほど、誤りも即時に全部へ届く。

悪い例と直した例。架空の API の入口が、配られた割当の方針を読む

// 悪い例 方針の項目がそろっている前提で読む。Limit が空なら異常終了
limit := p.Quota.Limit.Value

// 直した例 新しい道は旗で閉じ、読む時に形を確かめる
if !flags.Enabled("quota_check_v2", req.Project) {   // 既定は無効
    return legacyQuota(req)
}
if p.Quota == nil || p.Quota.Limit == nil {
    metrics.Inc("policy_invalid")                    // 数えて知らせる
    return legacyQuota(req)                          // この方針だけ使わない
}
limit := p.Quota.Limit.Value
  • どちらへ倒すかは確かめごとに決める。割当の確かめが動かない時に要求を通すのは、使い過ぎを一時的に許すだけで済む。認可の確かめが動かない時は拒む。失敗の時に開く作りの危うさは A10 例外的な状況への不適切な対応 にある。Google が通す側に倒すとしたのは、Service Control の中の切り離した機能の確かめである[1]。
  • NULL の参照のような誤りは、捕まえて続けるより、読む前に確かめる方が確かだ。捕まえる作りは、別の箇所の同じ誤りを見逃す。

架空の方針の配信。地域を輪に分け、先の輪で異常が出たら止める

policy_rollout:
  rings:
    - name: internal          # 社内の計画だけ
      regions: [region-a]
      bake: 30m
    - name: one-region
      regions: [region-b]
      bake: 1h
    - name: global
      regions: all
  halt_if:
    crash_loop_tasks: "> 0"   # 1つでも再起動の繰り返しが出たら止める
    api_5xx_rate: "+0.1%"
  on_halt: restore_previous

再起動と再試行の待ち。架空の読み込み

for attempt := 0; ; attempt++ {
    if err := loadPolicies(); err == nil {
        break
    }
    ceil := min(base<<attempt, maxDelay)
    time.Sleep(time.Duration(rand.Int63n(int64(ceil))))   // 0 から上限までのどこか
}

待ちの上限だけを伸ばすと、全部のタスクが同じ時に再び来る。上限までの間に散らすと、押し寄せが平らになる。AWS の設計の記事は、この散らし方を Full Jitter と呼び、散らさない指数的な待ちより、頼る先の負荷も全体の仕事も大きく減ると示した[5]。

緩和の策
  • 止める赤いボタンを、変更ごとに用意し、出す前に押して効くことを試す。この件では10分で原因を突き止め、ボタンの準備に入れた[1]。
  • 大事な仕組みの変更を止める凍結の手順を持つ。Google は回復の直後に、Service Control の変更と手作業の方針の配信を止めた[1]。
  • 使う側は、監視と連絡の道を、監視される雲の外にも持つ。この件で Google Cloud の上の監視が落ち、合図を失った顧客がいた[1]。
  • 試験が通ったことは、新しい道を通ったことを示さない。AIが書いたコードと試験も、どの道を通ったかで読む。読み方は AIの出力を確かめる にある。

配った設定で全部が同時に落ちた型は、CrowdStrike 2024年 と Cloudflare 2025年 にもある。

参照

  1. Multiple GCP products are experiencing Service issues の Incident Report Google Cloud Service Health、2025年6月13日 16時45分 PDT
  2. 同じ頁の Mini Incident Report Google Cloud Service Health、2025年6月12日 23時34分 PDT
  3. 同じ頁の障害の期間と途中の更新 Google Cloud Service Health、2025年6月12日
  4. Addressing Cascading Failures Site Reliability Engineering、Google
  5. Exponential Backoff And Jitter AWS Architecture Blog