Go 프로파일링(pprof 사용)
Source: Dev.to
pprof란?
pprof는 Go에 내장된 프로파일링 도구로, 애플리케이션의 런타임 데이터를 수집하고 분석할 수 있습니다. CPU 사용량, 메모리 할당, goroutine, 블로킹 연산 등 다양한 정보를 확인할 수 있습니다.
쉽게 말해, pprof는 다음과 같은 질문에 답합니다:
- 왜 내 애플리케이션이 느린가?
- CPU 시간이 어디에 사용되고 있는가?
- 어떤 부분이 메모리를 많이 할당하고 있는가?
- goroutine이 새어나가고 있는가?
스포일러: pprof는 코드를 마법처럼 최적화해 주지는 않습니다. 어디서 실수했는지 알려줄 뿐입니다.
pprof 작동 방식
pprof는 두 단계로 동작합니다:
- 수집 – 런타임 동안 애플리케이션에서 메트릭을 모읍니다.
- 분석 –
go tool pprof를 사용해 수집된 메트릭을 살펴봅니다.
런타임에 Go는 실행을 샘플링하고 메트릭을 기록합니다. 이 샘플들은 프로파일로 집계되어 pprof 명령으로 시각화하고 탐색할 수 있습니다. 내부적으로 Go는 통계적 프로파일링을 수행합니다: 프로그램을 주기적으로 중단하고 그 순간 실행 중이던 코드를 기록합니다. 시간이 지나면서 이러한 스냅샷이 리소스 사용량에 대한 정확한 그림을 만들어 줍니다.
프로파일링을 간단히 활성화하려면 내장 HTTP 서버를 노출하면 됩니다:

이렇게 하면 /debug/pprof/ 아래에 프로파일링 엔드포인트가 노출됩니다:
/debug/pprof/profile– CPU/debug/pprof/heap– 메모리- …그 외 여러 엔드포인트
프로파일 수집
/debug/pprof/profile 같은 pprof 엔드포인트에 접근하면, 응답은 바이너리 protobuf(보통 gzip 압축) 형태이며, 원시 샘플 데이터, 스택 트레이스, 카운터, 타임스탬프 등을 포함합니다. 이는 인간이 읽을 수 있는 보고서가 아닙니다.
pprof는 이 원시 데이터를 디코딩하고, 집계하여 읽기 쉬운 형태로 보여주는 도구입니다.
프로파일 분석
먼저 pprof CLI를 설치합니다:
go install github.com/google/pprof@latest
$GOPATH/bin에 바이너리가 설치된 것을 확인할 수 있습니다.
다음으로 웹 서버를 실행한 상태에서 CPU 프로파일을 10초 동안 가져옵니다:
go tool pprof http://localhost:8080/debug/pprof/profile?seconds=10
설정이 올바르게 되어 있으면, pprof 인터랙티브 쉘에 들어가 top, list, web 등 다양한 명령을 실행할 수 있습니다(전체 명령 목록은 여기 참고).
The Big Bad Boy
CPU를 많이 잡아먹는 엔드포인트가 있다고 가정해봅시다, 예를 들어 /work.
부하를 걸어봅니다:
curl http://localhost:8080/work
이 작업을 반복하거나 hey 혹은 ab 같은 부하 생성기를 사용할 수 있습니다.
실행 중인 서버에서 10초짜리 CPU 프로파일을 수집합니다:
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=10
pprof 쉘 안에서 CPU를 가장 많이 사용하는 함수들을 확인하려면:
(pprof) top
예시 출력:
Showing nodes accounting for 7470ms, 92.45% of 8080ms total
Dropped 2 nodes (cum <= 40.40ms)
Showing top 10 nodes out of 35
flat flat% sum% cum cum%
2030ms 25.12% 25.12% 2030ms 25.12% math.archExp
1570ms 19.43% 44.55% 1570ms 19.43% math.IsInf (inline)
1500ms 18.56% 63.12% 2830ms 35.02% math.log
560ms 6.93% 70.05% 5800ms 71.78% math.pow
430ms 5.32% 75.37% 1050ms 13.00% math.sin
330ms 4.08% 79.46% 330ms 4.08% runtime.pthread_cond_signal
320ms 3.96% 83.42% 1560ms 19.31% math.frexp
290ms 3.59% 87.00% 290ms 3.59% math.Float64frombits (inline)
220ms 2.72% 89.73% 220ms 2.72% math.IsNaN (inline)
220ms 2.72% 92.45% 230ms 2.85% math.normalize (inline)
누적 비용을 보려면:
(pprof) top -cum
출력 일부:
Showing nodes accounting for 2170ms, 26.86% of 8080ms total
Dropped 2 nodes (cum <= 40.40ms)
Showing top 10 nodes out of 35
flat flat% sum% cum cum%
110ms 1.36% 1.36% 7750ms 95.92% main.heavyComputation
0 0% 1.36% 7750ms 95.92% main.main.func1
0 0% 1.36% 7750ms 95.92% net/http.(*ServeMux).ServeHTTP
0 0% 1.36% 7750ms 95.92% net/http.(*conn).serve
0 0% 1.36% 7750ms 95.92% net/http.HandlerFunc.ServeHTTP
0 0% 1.36% 7750ms 95.92% net/http.serverHandler.ServeHTTP
0 0% 8.29% 2830ms 35.02% math.Log (inline)
main.heavyComputation 함수가 대부분의 CPU 사용량을 차지하고 있습니다—우리의 “Big Bad Boy”.
다른 측면 프로파일링
메모리, 블록, 뮤텍스, goroutine 프로파일도 같은 방식으로 수집하고 분석할 수 있습니다.
메모리 (heap)
go tool pprof http://localhost:6060/debug/pprof/heap
이 명령을 통해 할당을 탐색하고, 메모리 누수를 식별하며, 어떤 함수가 가장 많은 메모리를 차지하는지 확인할 수 있습니다. top, list, web 등 CPU 프로파일에서 사용한 명령들을 힙 프로파일에도 동일하게 적용할 수 있습니다.