Backend
Go 가비지 컬렉터(GC) 이해와 튜닝 경험
Go GC 튜닝에서 실제로 효과가 큰 순서와 운영 체크포인트를 정리합니다.
Go 가비지 컬렉터(GC) 이해와 튜닝 경험
먼저 결론
GC 문제는 보통 파라미터 문제가 아니라 할당 패턴 문제입니다. 우선순위는 아래 순서가 맞습니다.
- 할당량 자체 줄이기
GOMEMLIMIT설정- 마지막에
GOGC미세 조정
관측 없이 튜닝하지 않기
GODEBUG=gctrace=1 ./myapp
함께 보는 지표:
go_gc_duration_secondsgo_memstats_heap_alloc_bytesgo_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를 맞추는 순서가 가장 재현 가능했습니다.