본문으로 건너뛰기

[Loki] 쿼리 엔진 캐시 정확성 테스트 추가

PR 링크: grafana/loki#21113 상태: Merged | 변경: +295 / -9

들어가며

Grafana Loki의 새로운 쿼리 엔진에 결과 캐시(results cache) 기능이 추가되면서, 캐시된 결과가 캐시되지 않은 결과와 동일한지 검증하는 정확성 테스트가 필요해졌습니다. 이 PR은 실제 쿼리를 두 번(캐시 미스 + 캐시 히트) 실행하고 결과를 비교하는 통합 테스트를 추가합니다.

핵심 코드 분석

CountingExecutor: 실제 실행 횟수 추적

type countingExecutor struct {
    inner *engine.Engine
    n     atomic.Int64
}

func (e *countingExecutor) Execute(ctx context.Context, params logql.Params) (logqlmodel.Result, error) {
    e.n.Add(1)
    return e.inner.Execute(ctx, params)
}

실제 엔진을 래핑하여 Execute 호출 횟수를 추적합니다. 캐시가 올바르게 동작하면 두 번째 요청에서 Execute가 호출되지 않아야 합니다.

캐시 정확성 테스트 흐름

테스트는 각 쿼리 테스트 케이스에 대해:

  1. 첫 번째 요청: 캐시 미스 → 엔진 실행 → 결과 캐싱
  2. 두 번째 요청: 캐시 히트 → 캐시에서 결과 반환
  3. 두 결과를 tolerance 기반으로 비교

QueryExecutor 인터페이스 공개

// QueryExecutor is the interface satisfied by [Engine], exposed for testing.
type QueryExecutor interface {
    Execute(ctx context.Context, params logql.Params) (logqlmodel.Result, error)
}

// HandlerFromExecutor is like [Handler] but accepts any [QueryExecutor].
func HandlerFromExecutor(cfg Config, logger log.Logger, exec QueryExecutor, limits Limits, reg prometheus.Registerer) (http.Handler, error) {
    return executorHandler(cfg, logger, exec, limits, reg)
}

기존의 비공개 queryExecutor 인터페이스를 QueryExecutor로 공개하고, HandlerFromExecutor를 추가하여 테스트에서 mock executor를 주입할 수 있게 했습니다.

왜 이게 좋은가

  1. 캐시 버그 조기 발견: 캐시된 결과와 실제 실행 결과가 다른 경우(직렬화/역직렬화 오류, 시간 버킷 경계 문제 등)를 자동으로 감지합니다.
  2. 회귀 방지: 캐시 로직 변경 시 정확성이 보장됩니다. 특히 부동소수점 비교에 tolerance를 적용하여 false positive를 방지합니다.
  3. 빈 결과 검증: empty-result 태그가 붙은 테스트 케이스에 대해 결과가 실제로 비어있는지도 검증하여 쿼리 템플릿 오류를 잡습니다.

캐시는 성능 최적화의 핵심이지만, 정확성 없는 캐시는 오히려 위험합니다. 이 테스트는 캐시가 성능과 정확성을 동시에 보장하는지 검증하는 중요한 안전망입니다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글