sayu.day
Backend

Go 가비지 컬렉터(GC) 이해와 튜닝 경험

Go GC 튜닝에서 실제로 효과가 큰 순서와 운영 체크포인트를 정리합니다.

발행 2025년 12월 30일2230

같은 주제에서 이어 읽기

Enterprise Go 시리즈 #8: Observability와 Debugging

Backend 안에서 이어지는 글

먼저 결론

GC 문제는 보통 파라미터 문제가 아니라 할당 패턴 문제입니다. 우선순위는 아래 순서가 맞습니다.

  1. 할당량 자체 줄이기
  2. GOMEMLIMIT 설정
  3. 마지막에 GOGC 미세 조정

관측 없이 튜닝하지 않기

GODEBUG=gctrace=1 ./myapp

함께 보는 지표:

  • go_gc_duration_seconds
  • go_memstats_heap_alloc_bytes
  • go_memstats_next_gc_bytes

핵심은 "GC가 자주 도는 이유"를 찾는 것입니다.

효과가 컸던 개선 4가지

1) 불필요한 할당 제거

  • append 대상 slice preallocate
  • 핫패스의 string <-> []byte 변환 최소화
  • 중간 객체 생성 줄이기

2) 객체 재사용

sync.Pool은 짧은 생명주기 버퍼에만 제한적으로 사용합니다. 영구 캐시 용도로 쓰면 오히려 디버깅 비용이 커집니다.

3) 메모리 한계 명시

GOMEMLIMIT=2GiB ./myapp

컨테이너 환경에서는 거의 필수입니다. OOM 직전 폭주 패턴을 완화합니다.

4) GOGC 조정

GOGC=100 # 기본
GOGC=50  # 메모리↓ CPU↑
GOGC=200 # 메모리↑ CPU↓

경험상 50~150 범위에서 트래픽 특성에 맞추는 경우가 많습니다.

실제 장애 패턴

  • p99 튐 + GC cycle 급증: 임시 객체 폭증
  • 배치 구간 OOM: batch size 과대 + 중간 결과 적재

해결은 공통적으로 "할당 구조 변경 + 한계값 설정"이었습니다.

하지 말아야 할 것

  • 요청 경로에서 runtime.GC() 호출
  • 근거 없는 극단값 설정 (GOGC=10, 1000)
  • 프로파일 없이 파라미터만 반복 변경

요약

Go GC 튜닝은 숫자 놀이가 아니라 메모리 설계 작업입니다. 할당 hot path를 먼저 고치고, 그 다음에 GOMEMLIMIT, 마지막으로 GOGC를 맞추는 순서가 가장 재현 가능했습니다.

다음 읽기

이 생각이 이어지는 방향

Backend 더 보기
공유

읽은 뒤의 대화

읽은 뒤의 생각을 이어갑니다

질문, 반론, 조용한 후속 메모를 이 글 아래에 남길 수 있습니다.

sayu.day는 생각과 작업의 흔적을 천천히 정리하는 개인 출판물입니다.
직접 겪고 검토한 내용, 다시 읽을 만한 아이디어, 작업하며 남긴 메모를 모읍니다.
시간이 지난 글은 현재의 판단과 다를 수 있어 업데이트 맥락을 함께 남깁니다.

© 2026 sayu.day