[loki] Grafana Loki 성능 최적화: 파일 핸들 풀링을 통한 I/O 오버헤드 개선
PR 링크: grafana/loki#24037 상태: Merged | 변경: +115 / -57
들어가며
Grafana Loki는 대규모 로그 데이터를 처리하기 위해 TSDB(Time Series Database) 인덱스를 사용합니다. 기존에는 인덱스 파일을 읽을 때마다 파일을 열고 닫는 과정이 반복되었으며, 이는 특히 빈번한 쿼리가 발생하는 환경에서 상당한 I/O 오버헤드를 유발했습니다. 이번 PR(chore: Pool file handles)은 이러한 문제를 해결하기 위해 '파일 핸들 풀링(File Handle Pooling)' 메커니즘을 도입했습니다.
코드 분석
1. 설정 및 인터페이스 확장 (pkg/storage/stores/shipper/indexshipper/shipper.go)
가장 먼저 사용자가 풀링 기능을 제어할 수 있도록 새로운 설정 플래그를 추가했습니다.
// Before
f.StringVar((*string)(&cfg.IndexReaderMode), prefix+"shipper.index-reader-mode", string(DefaultIndexReaderMode), ...)
// After
f.UintVar(&cfg.StreamingIndexMaxIdleFileHandles, prefix+"shipper.streaming-index-max-idle-file-handles", DefaultStreamingIndexMaxIdleFileHandles, ...)
또한, 기존의 단순한 모드 설정을 IndexReaderOptions 구조로 추상화하여, mmap과 stream 모드에 따른 옵션을 유연하게 처리할 수 있도록 변경했습니다.
2. 스트리밍 리더 옵션 도입 (pkg/storage/stores/shipper/indexshipper/tsdb/index/index.go)
기존에는 mmap 방식에 의존하던 로직을 tsdbindex.ReaderOptions 인터페이스를 통해 StreamOptions를 지원하도록 확장했습니다. 이를 통해 파일 핸들을 매번 닫지 않고 일정 개수만큼 캐싱(Pooling)하여 재사용할 수 있게 되었습니다.
왜 이게 좋은가
이 최적화의 핵심은 '파일 시스템 호출(syscall)의 최소화'입니다. 파일을 열고 닫는 작업은 커널 레벨에서 비용이 큰 작업입니다. 특히 NewStreamFileReader 벤치마크 결과를 보면 성능 향상이 매우 뚜렷합니다.
- 성능 수치:
NewStreamFileReader의sec/op가 약 63.61% 개선되었으며, 메모리 할당(allocs/op) 또한 14.29% 감소했습니다. - 교훈: 반복적인 리소스 생성/소멸이 발생하는 I/O 작업에서는 '풀링(Pooling)' 패턴이 매우 효과적입니다. 특히 Loki와 같이 대량의 인덱스 파일을 다루는 시스템에서는 파일 핸들 캐싱이 쿼리 응답 속도와 시스템 전체 처리량(Throughput)에 결정적인 영향을 미칩니다.
이번 변경은 Loki가 mmap 의존성에서 벗어나 더 유연한 스트리밍 인덱스 읽기 방식으로 나아가는 중요한 최적화 단계입니다.
참고 자료
- https://pkg.go.dev/os#File
- https://github.com/grafana/loki/blob/main/pkg/storage/stores/shipper/indexshipper/shipper.go
⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.
관련 포스트
PR Analysis 의 다른글
- 이전글 [sglang] [AMD MI355X] DeepSeek-V4 최적화: FP8 Quantization의 불필요한 Copy 제거하기
- 현재글 : [loki] Grafana Loki 성능 최적화: 파일 핸들 풀링을 통한 I/O 오버헤드 개선
- 다음글 [flashinfer] FlashInfer의 PrimTS를 활용한 고성능 Block-Sparse Attention 최적화
댓글