세그먼트 크기 최적화(Segment size optimization)

세그먼트 크기 최적화(Segment size optimization)

Apache Druid에서는 세그먼트 크기 최적화가 무척 중요해요. 이 문서에서는 왜 세그먼트 크기를 최적화해야 하는지, 권장하는 행 수와 바이트 크기, 그리고 컴팩션(compaction)으로 최적화하는 방법을 설명드릴게요.

출처: 문서

본문

Apache Druid에서는 세그먼트 크기를 최적화하는 것이 중요해요. 그 이유는 다음과 같아요:

  • Druid는 데이터를 세그먼트로 저장합니다. best-effort 롤업(roll-up) 모드를 사용한다면, 세그먼트 크기를 늘리는 것이 추가 집계를 유발해서 dataSource 크기를 줄여줄 수 있어요.
  • 쿼리가 제출되면 그 쿼리는 쿼리의 입력 세그먼트를 보유한 모든 Historical과 실시간 태스크로 분산됩니다. 각 프로세스와 태스크는 자체 처리 스레드 풀(processing thread pool)에서 스레드 하나를 골라 단일 세그먼트를 처리해요. 세그먼트 크기가 너무 크면 데이터가 데이터 서버들 사이에 잘 분산되지 않아서, 쿼리 처리 중 가능한 병렬 처리 정도(degree of parallelism)가 낮아질 수 있어요.
  • 반대의 극단인 경우, 세그먼트 크기가 너무 작으면 쿼리당 더 많은 세그먼트를 처리하는 스케줄링 오버헤드가 성능을 떨어뜨릴 수 있어요. 각 세그먼트를 처리하는 스레드들이 처리 풀의 고정된 슬롯을 두고 경쟁하기 때문입니다.

가능하면 수집 시점에 세그먼트 크기를 최적화하는 것이 최선이에요. 다만 스트림 수집의 경우 유입되는 데이터 양이 시간에 따라 달라질 수 있어서 항상 쉬운 것은 아니에요. 이런 경우에는 먼저 최적이 아닌 크기로 세그먼트를 만든 다음, 나중에 컴팩션(compaction)을 사용해 최적화할 수 있어요.

세그먼트를 최적화할 때 다음 사항을 고려해야 해요.

  • 세그먼트당 행 수: 일반적으로 각 세그먼트에 약 500만 행을 두는 것이 권장됩니다. 이 설정은 아래의 "세그먼트 바이트 크기"보다 보통 더 중요해요. Druid는 각 세그먼트를 처리할 때 단일 스레드를 사용하므로, 이 설정이 각 스레드가 처리하는 행 수를 직접 제어하고, 나아가 쿼리 실행이 얼마나 잘 병렬화되는지를 결정하기 때문입니다.
  • 세그먼트 바이트 크기: 300~700MB로 설정하는 것이 권장됩니다. 이 값이 "세그먼트당 행 수"와 맞지 않으면, 이 값보다는 세그먼트당 행 수를 최적화하는 것을 고려하세요. 참고로 일부 딥 스토리지 구현은 세그먼트 크기에 상한을 두기도 해요. 예를 들어 S3 딥 스토리지는 5GB 상한을 둡니다.

위 권장 사항은 일반적으로 잘 동작하지만, 최적 설정은 워크로드에 따라 달라질 수 있어요. 예를 들어 대부분의 쿼리가 무겁고 각 행을 처리하는 데 오래 걸린다면, 쿼리 처리를 더 병렬화할 수 있도록 세그먼트를 더 작게 만드는 것이 좋을 수 있어요. 세그먼트 크기를 최적화한 후에도 여전히 성능 문제가 보인다면, 워크로드에 맞는 최적 설정을 찾아야 합니다.

컴팩션이 필요한지 확인하는 방법은 여러 가지가 있어요. 그중 하나는 System Schema를 사용하는 것이에요. 시스템 스키마는 segments 테이블을 포함해 현재 시스템 상태에 대한 여러 테이블을 제공합니다. 아래 쿼리를 실행하면 게시된 세그먼트의 평균 행 수와 평균 크기를 얻을 수 있어요:

SELECT
  "start",
  "end",
  version,
  COUNT(*) AS num_segments,
  AVG("num_rows") AS avg_num_rows,
  SUM("num_rows") AS total_num_rows,
  AVG("size") AS avg_size,
  SUM("size") AS total_size
FROM
  sys.segments A
WHERE
  datasource = 'your_dataSource' AND
  is_published = 1
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3 DESC

주의: 쿼리 결과에는 가려진(overshadowed) 세그먼트가 포함될 수 있어요. 이 경우 interval(start와 end 쌍)당 최대 버전 행만 보도록 하는 것도 고려해 보세요.

세그먼트에 컴팩션이 필요하다는 것을 알게 되면 다음 두 가지 옵션을 고려할 수 있어요:

  • Coordinators의 자동 컴팩션(automatic compaction)을 켜는 것. Coordinator가 주기적으로 컴팩션 태스크를 제출해 작은 세그먼트를 다시 인덱싱합니다. 자동 컴팩션을 활성화하려면 Coordinator의 동적 구성(dynamic configuration)을 통해 각 dataSource에 대해 구성해야 해요. 자세한 내용은 Automatic compaction 문서를 참고하세요.
  • 주기적인 배치 수집 잡(batch ingestion jobs)을 실행하고 dataSource inputSpec을 사용해 Kafka 인덱싱 태스크가 생성한 세그먼트에서 읽는 것. 많은 세그먼트를 병렬로 컴팩션하려면 이 방식이 유용할 수 있어요. 이에 대한 자세한 내용은 data management 페이지의 Updating existing data 섹션에서 확인할 수 있어요.

더 알아보기 (Learn more)

  • Compaction: 컴팩션 개요와 수동 컴팩션 태스크 제출 방법.
  • Automatic compaction: 자동 컴팩션 활성화 및 구성 방법.