컴팩션

컴팩션 (Compaction)

Apache Druid의 쿼리 성능은 최적으로 크기가 잡힌 segment에 달려 있어요. 컴팩션은 Druid 데이터베이스의 segment 크기를 최적화하는 전략 중 하나예요. 컴팩션 task는 주어진 시간 interval의 기존 segment 집합을 읽어 데이터를 새 "compacted" segment 집합으로 결합해요.

출처: 문서

본문

Apache Druid의 쿼리 성능은 최적으로 크기가 잡힌 segment에 달려 있어요. 컴팩션은 Druid 데이터베이스의 segment 크기를 최적화하기 위해 사용할 수 있는 전략 중 하나예요. 컴팩션 task는 주어진 시간 interval의 기존 segment 집합을 읽어 데이터를 새 "compacted" segment 집합으로 결합해요. 어떤 경우에는 compacted segment가 더 크지만 개수가 더 적어요. 다른 경우에는 compacted segment가 더 작을 수도 있어요. 컴팩션은 성능을 높이는 경향이 있는데, 최적화된 segment는 ingestion과 querying 경로에서 segment당 처리량과 메모리 오버헤드가 더 적기 때문이에요.

컴팩션 가이드라인

segment 최적화를 위해 컴팩션을 고려해야 할 몇 가지 경우가 있어요:

  • Streaming ingestion에서는 데이터가 시간 순서대로 도착하지 않아 작은 segment가 많이 생길 수 있어요.
  • native batch ingestion에 appendToExisting로 데이터를 append해 최적이 아닌 segment를 만들 때.
  • 병렬 batch indexing에 index_parallel을 사용하고 병렬 ingestion task가 작은 segment를 많이 만들 때.
  • 잘못 설정된 ingestion task가 과대한 segment를 만들 때.

기본적으로 컴팩션은 segment의 기본 데이터를 수정하지 않아요. 하지만 쿼리 성능을 개선하려고 컴팩션 중 데이터를 수정하고 싶은 경우가 있어요:

  • ingestion 후에 시간 interval에 대한 데이터가 sparse하다는 것을 깨닫게 되면, 컴팩션으로 segment granularity를 높일 수 있어요.
  • 오래된 데이터에 대해 세밀한 granularity가 필요 없다면, 컴팩션으로 오래된 segment를 더 굵은 query granularity로 바꿀 수 있어요. 예를 들어 minute에서 hour로, 또는 hour에서 day로요. 이렇게 하면 오래된 데이터에 필요한 저장 공간이 줄어들어요.
  • dimension 순서를 바꿔 정렬을 개선하고 segment 크기를 줄일 수 있어요.
  • 컴팩션에서 사용하지 않는 컬럼을 제거하거나, 오래된 데이터에 대해 집계 metric을 구현할 수 있어요.
  • segment rollup을 best-effort rollup이 있는 dynamic partitioning에서 perfect rollup이 있는 hash 또는 range partitioning으로 바꿀 수 있어요. rollup에 대한 자세한 내용은 perfect vs best-effort rollup을 참고하세요.

컴팩션이 모든 상황에서 성능을 개선하지는 않아요. 예를 들어 ingestion task마다 데이터를 다시 쓴다면 컴팩션을 사용할 필요가 없어요. 컴팩션이 환경에서 도움이 될지 판단하는 추가 지침은 Segment optimization을 참고하세요.

컴팩션 실행 방법

자동 컴팩션(auto-compaction)은 대부분의 사용 사례에서 동작하며 첫 번째 선택지여야 해요.

Coordinator는 segment search policy를 사용해 컴팩션할 segment를 최신에서 오래된 순서로 주기적으로 식별해요. Coordinator가 컴팩션되지 않은 segment나, 다른·변경된 spec으로 컴팩션된 segment를 발견하면, 그 segment들을 포함한 시간 interval에 대해 컴팩션 task를 제출해요.

자세한 내용은 Automatic compaction을 참고하세요.

컴팩션에 대한 더 많은 제어가 필요한 경우, 컴팩션 task를 수동으로 제출할 수 있어요. 예를 들어:

  • 자동 컴팩션이 사용 가능한 task 슬롯 한계에 부딪혀서, task들이 이전 자동 컴팩션 task의 완료를 기다리고 있는 경우. 수동 컴팩션은 사용 가능한 모든 task 슬롯을 사용할 수 있으므로, 더 많은 interval에 더 많은 동시 task를 제출하면 컴팩션을 더 빨리 완료할 수 있어요.
  • 특정 시간 범위에 컴팩션을 강제하고 싶거나, 시간 순서가 아닌 데이터를 컴팩션하고 싶은 경우.

수동 컴팩션 task에 대한 자세한 내용은 수동 컴팩션 task 설정을 참고하세요.

데이터 나이에 따라 다른 컴팩션 설정이 필요한 고급 데이터 수명주기 관리 — 예를 들어 segment granularity 굵히기, 오래된 행 삭제, 시간에 따른 압축 변경 — 가 필요하다면 Cascading reindexing을 참고하세요.

컴팩션 시 데이터 처리

컴팩션 중에 Druid는 원래 segment 집합을 compacted 집합으로 덮어써요. Druid는 데이터 일관성을 보장하기 위해 컴팩션되는 시간 interval도 잠궈요. 기본적으로 컴팩션 task는 기본 데이터를 수정하지 않아요. 컴팩션 task를 구성해서 query granularity를 바꾸거나 dimension을 추가·제거할 수 있어요. 즉, 쿼리 결과의 변경은 자동이 아닌 의도적인 변경의 결과여야 해요.

컴팩션 task의 ioConfig에서 dropExisting을 "true"로 설정하면, interval에 완전히 포함된 모든 기존 segment를 교체하도록 Druid를 구성할 수 있어요. 예시는 Implementation considerations 아래의 더 세밀한 granularity로 reindex하는 제안을 참고하세요.

info

WARNING: ioConfig의 dropExisting은 beta 기능이에요.

ingestion task가 컴팩션용으로 잠긴 시간 interval의 segment에 데이터를 써야 한다면, 기본적으로 ingestion task가 컴팩션 task보다 우선하고 컴팩션 task는 끝내지 못한 채 실패해요. 수동 컴팩션 task의 경우 input spec interval을 조정해서 ingestion과 컴팩션 사이의 충돌을 피할 수 있어요. 자동 컴팩션의 경우 skipOffsetFromLatest 키를 설정해서 현재 시간으로부터 자동 컴팩션 시작점을 조정하면 ingestion과 컴팩션 사이의 충돌 가능성을 줄일 수 있어요.

또 다른 옵션은 컴팩션 task를 ingestion task보다 높은 우선순위로 설정하는 거예요.

자세한 내용은 Avoid conflicts with ingestion을 참고하세요.

Segment granularity 처리

granularitySpec에서 segment granularity를 수정하지 않으면, Druid는 compacted segment의 granularity를 유지하려고 해요. segment들이 interval이 겹치지 않으면서 서로 다른 segment granularity를 가질 때, Druid는 각 segment에 대해 별도의 컴팩션 task를 만들어 compacted segment의 segment granularity를 유지해요.

컴팩션 전에 segment들이 서로 다른 segment granularity를 가지지만 interval이 다소 겹칠 때, Druid는 겹치는 interval의 시작과 끝을 찾아 compacted segment에 가장 가까운 segment granularity 수준을 사용하려고 해요.

예를 들어 두 개의 겹치는 segment를 생각해 봐요: day granularity를 가진 interval 01/01/2020-01/02/2020의 segment "A"와 interval 01/01/2020-02/01/2020의 segment "B". Druid는 겹치는 segment를 결합·컴팩션하려고 해요. 이 예시에서 두 segment의 가장 빠른 시작 시각은 01/01/2020, 가장 늦은 종료 시각은 02/01/2020이에요. Druid는 segment granularity가 다르더라도 segment들을 함께 컴팩션해요. Druid는 새 compacted segment에 month segment granularity를 사용해요. segment A의 원래 segment granularity가 day였더라도 말이에요.

Query granularity 처리

granularitySpec에서 query granularity를 수정하지 않으면, Druid는 compacted segment의 query granularity를 유지해요. 컴팩션 전에 segment들이 서로 다른 query granularity를 가질 때, Druid는 결과 compacted segment에 가장 세밀한 granularity 수준을 선택해요. 예를 들어 컴팩션 task가 day query granularity와 minute query granularity인 두 segment를 결합하면, 결과 segment는 minute query granularity를 사용해요.

info

Apache Druid 0.21.0 및 이전 버전에서는, Druid가 원래 segment의 query granularity와 무관하게 compacted segment의 granularity를 기본값 NONE으로 설정해요.

컴팩션에서 query granularity를 month 같은 더 세밀한 granularity에서 year 같은 더 굵은 query granularity로 구성하면, Druid는 원래 segment를 더 굵은 granularity로 overshadow해요. 새 segment는 더 굵은 granularity를 가지므로, 그 interval들에 대해 overshadow된 segment를 제거하기 위해 kill task를 실행하면 더 세밀한 granularity 데이터를 영구히 잃게 돼요.

Dimension 처리

Apache Druid는 스키마 변경을 지원해요. 따라서 같은 데이터소스의 일부라도 segment 간에 dimension이 다를 수 있어요. 서로 다른 스키마를 가진 segment를 참고하세요. 입력 segment들이 서로 다른 dimension을 가질 때, 결과 compacted segment는 입력 segment들의 모든 dimension을 포함해요.

입력 segment들이 동일한 dimension 집합을 가지더라도 dimension 순서나 dimension의 데이터 타입이 다를 수 있어요. 더 최근 segment일수록 선호되는 순서와 데이터 타입을 가질 가능성이 높으므로, 최근 segment의 dimension이 오래된 segment의 dimension보다 데이터 타입과 순서 면에서 앞서요.

dimension 순서를 제어하거나 dimension 타입의 특정 값을 보장하고 싶다면, 컴팩션 task spec에서 커스텀 dimensionsSpec을 구성할 수 있어요.

Rollup

Druid는 모든 입력 segment에 대해 rollup이 설정된 경우에만 출력 segment를 rollup해요.

자세한 내용은 Roll-up을 참고하세요.

segment가 rollup되었는지 확인하려면 Segment Metadata Queries를 사용할 수 있어요.

더 알아보기 (Learn more)

자세한 내용은 다음 주제를 참고하세요: