GOMAXPROCS, cgroups, and Containers
GOMAXPROCS, cgroups, and Containers
Overview
In Kubernetes and cgroup-limited environments, CPU quota ≠ host core count. Older Go versions defaulted GOMAXPROCS to machine CPUs, causing thrashing inside small pods. Modern Go improves cgroup awareness — still verify in your version and platform.
Diagram: Quota mismatch
flow:
[Pod]
|
v
[Bad]
[Pod]
|
v
[Good]
Failure Mode
Pod limit: 500m CPU (0.5 core)
GOMAXPROCS=16 (node size)
-> 16 threads fight for 0.5 CPU
-> latency noise, steal time, GC assists hurt more
Practices
// log at boot
slog.Info("sched", "gomaxprocs", runtime.GOMAXPROCS(0), "numCPU", runtime.NumCPU())- Prefer runtime auto-detect on current Go
- Or set explicitly from downward API / cgroup read
- Libraries like
automaxprocsexisted historically for this gap
Memory Side
Pair CPU limits with GOMEMLIMIT near container memory limit (leave headroom for non-Go RSS, caches).
GOMEMLIMIT=400MiB ./appExperiment
go run .package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("NumCPU", runtime.NumCPU())
fmt.Println("GOMAXPROCS", runtime.GOMAXPROCS(0))
}Run inside and outside a constrained container if you have Docker:
docker run --rm --cpus=0.5 -v "$PWD":/app -w /app golang:1.27 go run .What to notice: Compare printed values to --cpus quota on your platform/Go version.
Try next: Load test a CPU-bound endpoint with GOMAXPROCS 1 vs 4 under a 1 CPU quota.