Go 1.25 버전에 나타난 GOMAXPROCS 동작 변경

jaehan·2025년 8월 21일

GOMAXPROCS는 무엇인가?

Go 런타임 스케줄러의 G-M-P 모델에서 P(Processor)의 개수가 곧 GOMAXPROCS

  • G (goroutine): 작업 단위 (많아질 수 있음)

  • M (OS thread): 운영체제 스레드

  • P (processor): 동시에 실행 가능한 고루틴 수의 상한
    즉, GOMAXPROCS=4면 같은 순간에 최대 4개 고루틴이 실제 CPU에서 병렬로 돌아감

고루틴 수와 GOMAXPROCS는 별개. 고루틴은 수만 개여도, 동시에 실행되는 건 GOMAXPROCS까지만.

기존(≤1.24)/변경(1.25) GOMAXPROCS 동작

기존(≤1.24): 시작 시점의 논리 CPU 수(runtime.NumCPU()).

CPU Throttling → 영상에 나온 변규현님이 쓴 내용

runtime : make GOMAXPROCS cfs-aware on GOOS=linux #33803

NumCPU가 cgroup에 할당된 것보다 크게 잡히면 어떤 현상이 나타날까?

쓰로틀링이 발생하게 되고 해결방법은 아래와 같다.

https://github.com/uber-go/automaxprocs

Go 1.25 (리눅스/컨테이너):

Go 1.25 Release Notes 본문

Container-aware GOMAXPROCS¶

The default behavior of the GOMAXPROCS has changed. In prior versions of Go, GOMAXPROCS defaults to the number of logical CPUs available at startup (runtime.NumCPU). Go 1.25 introduces two changes:

On Linux, the runtime considers the CPU bandwidth limit of the cgroup containing the process, if any. If the CPU bandwidth limit is lower than the number of logical CPUs available, GOMAXPROCS will default to the lower limit. In container runtime systems like Kubernetes, cgroup CPU bandwidth limits generally correspond to the “CPU limit” option. The Go runtime does not consider the “CPU requests” option.

On all OSes, the runtime periodically updates GOMAXPROCS if the number of logical CPUs available or the cgroup CPU bandwidth limit change.

Both of these behaviors are automatically disabled if GOMAXPROCS is set manually via the GOMAXPROCS environment variable or a call to runtime.GOMAXPROCS. They can also be disabled explicitly with the GODEBUG settings containermaxprocs=0 and updatemaxprocs=0, respectively.

In order to support reading updated cgroup limits, the runtime will keep cached file descriptors for the cgroup files for the duration of the process lifetime.

이는,

  • 기본값 = min(논리 CPU 수, cgroup CPU 대역폭 제한) → 보통 K8s - resources.limits.cpu를 의미
  • 실행 중에도 주기적으로 갱신(limit/코어 수 변경 시)
  • requests는 고려하지 않음
  • 수동으로 한 번이라도 설정하면(환경변수 또는 코드) 이 자동 동작은 꺼짐.

Kubernetes 예시

resources:
  limits:
    cpu: "2"      # → 기본 GOMAXPROCS ≈ 2
  requests:
    cpu: "500m"   # → 런타임은 'requests'는 무시

limit이 없으면 호스트 노드의 논리 CPU 수가 기본값.

limit이 0.5 vCPU여도 GOMAXPROCS는 최소 1로 보정.

운영에서 왜 중요한가?

  • 스루풋/지연 예측 가능성↑: 컨테이너에 설정한 CPU limit만큼 동시 실행이 이뤄져 과도한 스레드 경쟁이 줄어드는 경향.

  • 실행 중 튜닝 주의: VPA/오토스케일 등으로 limit 변경 시 GOMAXPROCS도 함께 변동 → 워커 풀 크기 등을 GOMAXPROCS에 맞춰 동적으로 조정하는 코드가 있다면 의도치 않은 효과 가능.

기존 automaxprocs는?

Go 1.25의 컨테이너 인식 덕분에 대부분 불필요해질 것으로 보임

  • 둘 다 쓰면 중복/충돌 가능 → 하나만 선택(보통 기본 런타임 자동 권장).

Ref

https://www.gloriouscoding.com/93f57984-c47f-4683-8323-7bbecd457322

https://go.dev/doc/go1.25

profile
공부공부

1개의 댓글

comment-user-thumbnail
2025년 8월 22일

공유 감사드립니다

답글 달기