[Loki] TSDB 풀에 전체 슬라이스를 올바르게 반환하여 메모리 할당 99.6% 감소
PR #20969 - perf(tsdb): return full slice to pool after use
들어가며
Grafana Loki의 TSDB 모듈에서 슬라이스 풀(pool)이 제대로 작동하지 않는 미묘한 버그가 있었습니다. defer로 풀에 슬라이스를 반환할 때, defer 선언 시점의 값이 캡처되어 빈 슬라이스가 반환되는 문제였습니다. 이로 인해 풀이 사실상 무용지물이 되어 매번 새로운 메모리 할당이 발생했습니다.
핵심 코드 분석
Before
chks := ChunkMetasPool.Get()
defer ChunkMetasPool.Put(chks)
// chks에 데이터가 추가됨...
// 하지만 defer는 선언 시점의 chks 값(빈 슬라이스)을 캡처
After
chks := ChunkMetasPool.Get()
defer func() { ChunkMetasPool.Put(chks) }()
// 클로저가 실행 시점의 chks 값(채워진 슬라이스)을 참조
이 변경은 4개 파일에 걸쳐 동일한 패턴으로 적용되었습니다.
벤치마크 결과
| 벤치마크 | Before | After | 개선 |
|---|---|---|---|
| GetChunkRefs sec/op | 860.3us | 693.8us | -19.35% |
| GetChunkRefs B/op | 1374.7KB | 5.1KB | -99.63% |
| GetChunkRefs allocs/op | 27 | 18 | -33.33% |
| Volume sec/op | 280.0us | 275.6us | -1.56% |
| geomean B/op | 630.6KB | 248.6KB | -60.58% |
왜 이게 좋은가
- Go의 defer 동작 이해:
defer f(x)는 선언 시점에x를 평가하지만,defer func() { f(x) }()는 실행 시점에x를 평가합니다. 이 차이가 풀의 효과를 결정했습니다. - 메모리 할당 99.6% 감소: GetChunkRefs에서 1374KB에서 5KB로 메모리 사용이 극적으로 줄었습니다.
- 단 한 줄 변경의 위력: 각 수정은
defer Pool.Put(x)->defer func() { Pool.Put(x) }()한 줄 변경이지만, 성능 영향은 매우 큽니다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [pytorch] CI: vLLM 테스트/벤치마크 워크플로우를 CUDA 13.0으로 전환
- 현재글 : [Loki] TSDB 풀에 전체 슬라이스를 올바르게 반환하여 메모리 할당 99.6% 감소
- 다음글 [Loki] TSDBIndex.GetChunkRefs에서 불필요한 라벨 조회 제거
댓글