본문으로 건너뛰기

[Loki] 쿼리 엔진에 Parallelize 힌트 노드 추가

PR 링크: grafana/loki#19521 상태: Merged | 변경: +75 / -7

들어가며

Grafana Loki의 새로운 쿼리 엔진에 Parallelize 힌트 노드를 추가한 PR입니다. 이 노드는 스케줄러에게 "이 하위 브랜치는 병렬로 실행할 수 있다"는 힌트를 제공합니다. 현재는 실행 시 무시되지만, 향후 스케줄러가 이 노드를 기반으로 작업을 분배할 수 있는 기반을 마련합니다.

핵심 코드 분석

Parallelize 노드 정의

// Parallelize represents a hint to the engine to partition and parallelize the
// children branches of the Parallelize and emit results as a single sequence
// with no guaranteed order.
type Parallelize struct {
    id string
}

func (p *Parallelize) Type() NodeType { return NodeTypeParallelize }
func (p *Parallelize) Accept(v Visitor) error { return v.VisitParallelize(p) }

실행기에서의 처리: 힌트만 전달하고 즉시 통과

func (c *Context) executeParallelize(
    ctx context.Context,
    _ *physical.Parallelize,
    inputs []Pipeline,
) Pipeline {
    if len(inputs) == 0 {
        return emptyPipeline()
    } else if len(inputs) > 1 {
        return errorPipeline(ctx, fmt.Errorf(
            "parallelize expects exactly one input, got %d", len(inputs),
        ))
    }
    // Parallelize is a hint node to the scheduler for parallel execution.
    // If we see a Parallelize node in the plan, we ignore it and
    // immediately propagate up the input.
    return inputs[0]
}

플래너에서의 사용: MakeTable의 스캔을 Parallelize로 감싸기

// Scan work can be parallelized across multiple workers
var parallelize Node = &Parallelize{}
p.plan.graph.Add(parallelize)

var merge Node = &Merge{}
p.plan.graph.Add(merge)
for _, gr := range groups {
    if err := p.buildNodeGroup(gr, merge, ctx); err != nil {
        return nil, err
    }
}

// Add edge between parallelize and the final merge node
if err := p.plan.graph.AddEdge(dag.Edge[Node]{
    Parent: parallelize, Child: merge,
}); err != nil {
    return nil, err
}
return []Node{parallelize}, nil

왜 이게 좋은가

  1. 병렬화 기반 마련: 스캔 작업을 병렬로 분배하기 위한 메타데이터를 실행 계획에 포함시킵니다. 이는 향후 최적화 패스가 Parallelize 노드 내부의 작업을 여러 워커에 분배할 수 있게 합니다.
  2. 점진적 아키텍처 발전: 현재는 no-op이지만, 쿼리 엔진의 DAG 기반 실행 계획에 병렬성 의미론을 추가하여 향후 최적화의 진입점을 만듭니다.
  3. 기존 동작 보존: executeParallelize가 입력을 그대로 전달하므로, 기존 쿼리 실행에 영향이 없습니다.

이 PR은 즉각적인 성능 개선보다는 아키텍처적 기반을 마련하는 작업입니다. 물리 실행 계획에 병렬화 힌트를 포함시켜, 분산 스케줄러가 데이터 오브젝트 스캔을 여러 워커에 효율적으로 분배할 수 있는 길을 열었습니다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글