REALITY株式会社のバックエンドチームが、2026年8月深夜に複数回発生したGKE上のGoマイクロサービスのOOMKill障害を調査した記録です。該当PodはGuaranteed QoSでメモリ2Gi、GOMEMLIMITは1843MiB(リミットの90%)、GOGCはoffという設定でした。

調査の結果、原因はメモリリークではなくCPU飽和でした。ノードCPUが飽和しCFS throttlingが発生するとGCの進行が止まり、その間もメモリ割り当ては続くためGOMEMLIMITを突破(+186MiB)してOOMKillに至るというメカニズムです。実際、CPU throttle率が最も高かった15.3%のサービスが落ち、0.0%のサービスは無事でした。

さらにGOGC=offとGOMEMLIMIT併用では、ヒープゴール計算式が常にGOMEMLIMIT付近に固定され、memory limitまでの余白がわずか205MiBまで縮小する設計上の問題も判明しました。改善案としてGOGC="300"への変更を提示し、ヒープゴールを1710MiBから約1120MiBへ下げ余白を約780MiBまで拡大できる一方、GC CPUが5.4倍(Pod当たり+0.016 core)増える代償があると試算しています。

著者らのチームはこの障害以前、Goランタイムメトリクスの監視基盤なしで2年半運用していたと振り返っています。

出典が伝えている要点

  • 2026年8月の深夜に、GKE上のGoマイクロサービスのPodが複数回OOMKillされる障害が発生した
  • 該当Podのメモリリクエストとリミットは共に2Gi(Guaranteed QoS)に設定されていた
  • GOMEMLIMITは1843MiB(メモリリミットの90%)、GOGCはoffに設定されていた
  • ピークタイム3時間の実測で、go_gc_heap_live_bytes(ライブヒープ)は中央値99MiB、ワースト280MiBだった
  • 同期間のgo_gc_heap_goal_bytes(ヒープゴール)は中央値1710MiB、ワースト1777MiBだった
  • cgroupの実使用量はワーストで1831MiBに達した
  • 障害ノード上の3サービスのCPU throttle率は、落ちたサービスAが15.3%、危機一髪だったサービスBが6.2%、無事だったサービスCが0.0%だった
  • 原因はノードCPU飽和によるCFS throttlingがGCの進行を止め、メモリ割り当てが続行されGOMEMLIMITを突破(+186MiB)しmemory limit超過に至るというメカニズムだと結論づけている
  • GOGC=offとGOMEMLIMIT併用ではヒープゴール計算式がmin(∞, GOMEMLIMIT相当)=常にGOMEMLIMITに固定され、memory limitまでの余白が205MiBまで縮小する
  • 改善案としてGOGC=offからGOGC="300"への変更を提示し、ヒープゴールが1710MiBから約1120MiBへ、cgroup実使用が1831MiBから約1270MiBへ低下すると予測している
  • この変更によりmemory limit余白は約780MiBまで拡大する一方、GC CPU増加率は5.4倍(Pod当たり+0.016 core、リクエスト1coreの1.6%)という代償が見込まれるとしている
  • 著者らのチームはこの障害以前、Goランタイムメトリクスの監視基盤なしで2年半運用していたと述べている

原文より

ライブヒープが99MiBでも280MiBでも、ヒープゴールは常に1710MiB前後になります
GOMEMLIMITはソフトリミットで、GCを回すためのCPU時間がなければ機能しない

出典: zenn.dev

← 2026.09.02 の号を通しで読む