Go: コンテナの CPU 制限と GOMAXPROCS(Go 1.25 から cgroup の limit を見る)
Go 1.24 までは GOMAXPROCS の既定値がノードの論理 CPU 数だったので、CPU limit 2 の Pod でも 64 コアのノードなら 64 になり、CFS のスロットリングで遅くなっていた。Go 1.25 以降は cgroup の CPU limit を既定値に使う。ただし go.mod の go 行が 1.25 以上のときだけ。
どんな時に気にする?
- Kubernetes / ECS / Docker で
resources.limits.cpuを付けて Go のサービスを動かしている - p99 レイテンシが周期的に跳ねる、
container_cpu_cfs_throttled_seconds_totalが増えている - これまで
go.uber.org/automaxprocsを入れていた
確認と対処
- 実際の値を見る(起動ログに一行出しておくのが手軽)
go
slog.Info("runtime", "gomaxprocs", runtime.GOMAXPROCS(0), "numcpu", runtime.NumCPU()) - Go 1.25 以上でビルドし、go.mod を
go 1.25以上にする。ツールチェーンだけ新しくても、go.mod の go 行が古いと旧来の挙動のまま(GODEBUG の既定値が go 行で決まるため)。 - 1.25 以降の挙動
- cgroup の CPU limit(帯域制限)がコア数より小さければ、それを既定値にする
- limit やコア数が実行中に変わると、ランタイムが定期的に GOMAXPROCS を更新する
- 環境変数
GOMAXPROCSやruntime.GOMAXPROCS(n)で明示した場合は、どちらも働かない - 無効にしたいときは
GODEBUG=containermaxprocs=0/updatemaxprocs=0 - 明示設定を既定値に戻すには
runtime.SetDefaultGOMAXPROCS()(1.25 で追加)
- 1.25 に上げられない場合は、従来どおり
automaxprocsを blank import するか、GOMAXPROCSを limit に合わせて環境変数で渡す。
注意点
- 見るのは limit で、request は見ない。limit を付けていない Pod では、今でもノードのコア数になる。
- limit が小数(例: 1.5)のときは整数に切り上げて使う(細かい丸め方は公式の runtime ドキュメントで確認)。
- 1.25 に上げた後に automaxprocs を残していても動くが、二重管理になるので外してよい。
出典
- @amitsinha__07 · 2026-10-18
- Go 1.25 リリースノート(Runtime: container-aware GOMAXPROCS): go.dev/doc/go1.25#runtime