[Loki] 청크 재정렬 시 파이프라인 처리 바이패스로 CPU 최적화
PR 링크: grafana/loki#19211 상태: Merged | 변경: +46 / -3
들어가며
Loki 클러스터에서 청크 쓰기 경로에 많은 CPU 시간이 소비되고 있었다. 프로파일링 결과, 청크 재정렬(reorder) 시 사용하는 이터레이터가 쿼리용 파이프라인과 동일한 것을 사용하고 있어, NoopPipeline임에도 structured metadata 라벨 파싱과 관련 할당이 발생하고 있었다.
핵심 코드 분석
Context 기반 처리 비활성화 힌트
type processingDisabledKey struct{}
func processingDisabledContext(parent context.Context) context.Context {
return context.WithValue(parent, processingDisabledKey{}, true)
}
func isProcessingDisabled(ctx context.Context) bool {
v := ctx.Value(processingDisabledKey{})
disabled, _ := v.(bool)
return disabled
}
reorder에서 처리 비활성화 컨텍스트 사용
func (c *MemChunk) reorder() error {
from, to := c.Bounds()
ctx := processingDisabledContext(context.Background())
itr, err := c.Iterator(ctx, from, to.Add(time.Millisecond),
logproto.FORWARD, log.NewNoopPipeline().ForStream(labels.Labels{}))
// ...
}
이터레이터에서 조건부 처리 바이패스
type entryBufferedIterator struct {
// ...
skipProcessing bool
}
func (e *entryBufferedIterator) Next() bool {
for e.bufferedIterator.Next() {
if e.skipProcessing {
e.cur.Timestamp = time.Unix(0, e.currTs)
e.cur.Line = string(e.currLine)
e.cur.StructuredMetadata = logproto.FromLabelsToLabelAdapters(e.currStructuredMetadata)
return true
}
newLine, lbs, matches := e.pipeline.Process(e.currTs, e.currLine, e.currStructuredMetadata)
// ...
}
}
왜 이게 좋은가
- 불필요한 처리 제거: 재정렬은 로그 라인의 순서만 바꾸면 되는데, 기존에는 각 라인에 대해 파이프라인 처리(라벨 파싱, 메타데이터 처리)를 수행하고 있었다.
- Context 패턴 활용: Go의
context.Value를 활용한 힌트 전달로, 기존 인터페이스를 변경하지 않고도 동작을 제어할 수 있다. - 쓰기 경로 최적화: 청크가 out-of-order로 들어올 때마다 호출되는 재정렬 경로를 최적화하여, 고부하 환경에서의 CPU 사용량을 줄인다.
- 안전한 바이패스: 라벨이 변경되지 않는다는 것을 알고 있으므로,
pipeline.BaseLabels()를 한 번만 호출하여 재사용한다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [Loki] 쿼리 엔진 병렬 푸시다운 최적화 패스 추가
- 현재글 : [Loki] 청크 재정렬 시 파이프라인 처리 바이패스로 CPU 최적화
- 다음글 [Ray RLlib] 모듈별 루프에서 ALL_MODULES 처리량 메트릭을 루프 밖으로 이동하여 바이어스 제거
댓글