backend

Go 성능 분석과 최적화 입문: pprof로 병목 지점 찾는 방법

mirabo01 2026. 1. 24. 22:14

테스트까지 작성했다면, 이제 한 단계 더 나아가
**“이 코드가 얼마나 효율적으로 동작하는가”**를 고민하게 된다.

Go는 성능을 직접 튜닝하지 않아도
상당히 준수한 결과를 내는 편이지만,
트래픽이 늘거나 처리량이 중요해지는 순간
막연한 추측이 아니라 근거 있는 분석이 필요해진다.

이때 사용하는 도구가 바로 pprof다.

이 글에서는

  • pprof가 무엇인지
  • 어떤 성능 문제를 볼 수 있는지
  • 실무에서 최소한으로 활용하는 방법

을 중심으로 정리한다.


pprof는 무엇을 해주는 도구인가

pprof는 Go에서 제공하는 성능 프로파일링 도구다.
코드를 뜯어보거나 로그를 찍지 않아도, 다음 정보를 수집할 수 있다.

  • CPU를 어디서 많이 쓰는지
  • 메모리를 어디서 할당하는지
  • goroutine이 왜 늘어나는지
  • 어떤 함수가 병목인지

중요한 점은
**“느린 이유를 추측하지 않게 해준다”**는 것이다.


언제 pprof를 써야 할까

pprof는 이런 상황에서 의미가 있다.

  • 응답 속도가 점점 느려질 때
  • CPU 사용률이 비정상적으로 높을 때
  • 메모리 사용량이 계속 증가할 때
  • goroutine이 줄지 않고 쌓일 때

⚠️ 주의할 점
아직 문제가 없는데 미리 최적화하려고 pprof를 보는 건
대부분 시간 낭비가 된다.
문제가 관측된 이후에 사용하는 게 맞다.


pprof 사용 준비: net/http/pprof

가장 간단한 시작 방법은
표준 라이브러리의 net/http/pprof를 사용하는 것이다.

import _ "net/http/pprof"

그리고 HTTP 서버를 실행하면 끝이다.

go func() {
    http.ListenAndServe("localhost:6060", nil)
}()

이렇게 하면 다음 엔드포인트가 자동으로 열린다.

  • /debug/pprof/
  • /debug/pprof/profile
  • /debug/pprof/heap

[이미지: Go pprof HTTP 엔드포인트 구조]

실무에서는

  • 내부 포트에서만 열거나
  • 인증 뒤에서만 접근 가능하게

구성하는 게 일반적이다.


CPU 프로파일링 기본 흐름

CPU 사용량 분석은 보통 이렇게 진행한다.

go tool pprof http://localhost:6060/debug/pprof/profile
  • 기본 30초 동안 CPU 사용 정보 수집
  • 이후 pprof 콘솔 진입
(pprof)

이 상태에서 다양한 명령어를 사용할 수 있다.


가장 먼저 보는 명령어: top

(pprof) top
  • CPU를 가장 많이 사용한 함수 목록
  • “어디가 느린지”를 빠르게 파악 가능

실무에서는
이 결과만으로도
“건드려야 할 곳”이 명확해지는 경우가 많다.


호출 흐름 보기: web

(pprof) web
  • 함수 호출 관계를 그래프로 시각화
  • 어떤 경로에서 병목이 생겼는지 한눈에 확인

[이미지: pprof call graph 예시]

이 그래프를 보면
“생각보다 여기서 시간이 많이 쓰이네”라는 포인트가 거의 항상 나온다.


메모리 프로파일링(heap)

메모리 문제를 볼 때는 heap 프로파일을 사용한다.

go tool pprof http://localhost:6060/debug/pprof/heap

여기서 주로 보는 건 다음이다.

  • 메모리를 많이 할당하는 함수
  • 반복적으로 생성되는 객체
  • 해제되지 않고 남아 있는 구조

⚠️ 주의할 점
메모리 사용량이 많다고 해서
무조건 문제가 있는 건 아니다.
증가 추세(leak) 가 있는지가 핵심이다.


goroutine 프로파일링

goroutine이 계속 늘어난다면
대개 다음 중 하나다.

  • channel 송수신이 막힘
  • goroutine 종료 조건이 없음
  • context 취소 처리가 누락됨

pprof에서는 goroutine 상태도 확인할 수 있다.

go tool pprof http://localhost:6060/debug/pprof/goroutine

이 정보를 보면
어디서 goroutine이 멈춰 있는지 비교적 명확하게 드러난다.

[이미지: goroutine 상태 분포 예시]


벤치마크 테스트와 pprof

pprof는 서버뿐 아니라
벤치마크 테스트와도 함께 사용할 수 있다.

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(1, 2)
    }
}
go test -bench=. -cpuprofile=cpu.out
go tool pprof cpu.out

이 방식은

  • 특정 함수 성능 비교
  • 리팩터링 전/후 차이 확인

에 매우 유용하다.


pprof를 쓸 때 흔한 실수

⚠️ 자주 하는 실수

  • top 결과만 보고 바로 최적화
  • 전체 비율이 아닌 단일 수치만 보고 판단
  • IO 대기 시간을 CPU 문제로 착각

pprof 결과는 항상
“왜 이런 결과가 나왔는지”를 함께 해석해야 한다.


실무에서의 현실적인 사용 기준

실제로는 이렇게 사용하는 경우가 많다.

  1. 지표에서 이상 징후 발견
  2. pprof로 병목 후보 확인
  3. 한두 군데만 개선
  4. 다시 측정

모든 코드를 빠르게 만드는 게 아니라,
가장 영향이 큰 부분만 건드리는 것이 핵심이다.


정리

pprof는
성능 문제를 감으로 다루지 않게 해주는 도구다.

  • CPU, 메모리, goroutine 상태 확인 가능
  • 실제 데이터 기반으로 판단 가능
  • 최소한의 노력으로 큰 효과를 낼 수 있다

여기까지 왔다면,
Go 언어의 문법 → 구조 → 동시성 → 운영 → 성능까지
한 사이클을 전부 경험한 셈이다.

다음 단계로는

  • 간단한 API 서버 실습 시리즈
  • 실제 장애 사례 기반 성능 개선
  • Go로 작성한 프로젝트 회고

같은 콘텐츠로 확장해도 자연스럽다.