멀티테넌시
멀티테넌시 (Multitenancy)
Apache Druid는 사용자 대상 데이터 애플리케이션을 구동하는 데 자주 쓰이는데, 그럴 때 멀티테넌시(multitenancy)는 중요한 요구사항이 돼요. 이 문서에서는 Druid의 멀티테넌트 스토리지와 쿼리 기능을 소개할게요.
출처: 문서
본문
공유 datasource vs 테넌트별 datasource?
datasource는 Druid에서 데이터베이스 테이블에 해당하는 개념이에요. 멀티테넌트 워크로드는 테넌트마다 별도의 datasource를 사용할 수도 있고, tenant_id 차원을 이용해 여러 테넌트가 하나 이상의 datasource를 공유할 수도 있어요. 어떤 길을 갈지 결정할 때는 두 경로 모두 장단점이 있다는 점을 고려하세요.
테넌트별 datasource의 장점:
- 각 datasource가 자신만의 스키마, 백필(backfill), 파티셔닝 규칙, 데이터 로딩·만료 규칙을 가질 수 있어요.
- 일반적인 테넌트 쿼리에서 검사할 세그먼트 수가 더 적기 때문에 쿼리가 더 빨라질 수 있어요.
- 가장 많은 유연성을 얻을 수 있어요.
공유 datasource의 장점:
- 각 datasource는 실시간 인덱싱을 위해 각자 필요한 JVM을 요구해요.
- 각 datasource는 디스크에 각자 필요한 세그먼트 파일을 요구해요.
- 이런 이유 때문에 매우 많은 수의 작은 datasource를 두는 것은 낭비가 될 수 있어요.
한 가지 절충안은 테넌트 수보다는 적지만 여러 개의 datasource를 사용하는 거예요. 예를 들어 일부 테넌트는 파티셔닝 규칙 A를, 일부 테넌트는 규칙 B를 쓰게 하고, 두 개의 datasource에 테넌트를 나눠 담는 방식이에요.
공유 datasource 파티셔닝
멀티테넌트 클러스터가 공유 datasource를 사용한다면 대부분의 쿼리가 tenant_id 차원으로 필터링할 가능성이 높아요. 이런 종류의 쿼리는 데이터가 테넌트별로 잘 파티셔닝되어 있을 때 성능이 가장 좋아요. 이를 위한 방법은 몇 가지가 있어요.
배치 인덱싱에서는 다차원 파티셔닝 을 사용해 tenant_id 기준으로 데이터를 파티셔닝할 수 있어요. Druid는 항상 시간으로 먼저 파티셔닝하지만, 각 시간 버킷 안에서의 2차 파티션은 tenant_id가 돼요.
실시간 인덱싱에서는 Druid로 보내는 스트림을 조정해서 이 기능을 구현해요. 예를 들어 Kafka를 사용한다면 Kafka producer가 tenant_id의 해시로 토픽을 파티셔닝하도록 할 수 있어요.
데이터 분산 커스터마이징
Druid는 데이터를 분산하는 방식을 설정할 수 있게 해서 멀티테넌시를 추가로 지원해요. Druid의 Historical 프로세스는 티어(tier)로 구성할 수 있고, 어떤 세그먼트가 어떤 티어로 갈지 결정하는 규칙을 설정할 수 있어요. 여기서 한 가지 활용 사례는 최근 데이터가 오래된 데이터보다 더 자주 접근되는 경우예요. 티어링을 통해 최근 세그먼트를 더 강력한 하드웨어에 올려 성능을 높일 수 있어요. 최근 세그먼트의 두 번째 사본은 더 저렴한 하드웨어(다른 티어)에 복제할 수 있고, 오래된 세그먼트도 이 티어에 저장할 수 있어요.
높은 쿼리 동시성 지원
Druid는 세그먼트를 연산의 기본 단위로 사용해요. 프로세스는 세그먼트를 병렬로 스캔하고, 한 프로세스는 druid.processing.numThreads 만큼의 세그먼트를 동시에 스캔할 수 있어요. 클러스터에 코어를 더 추가하면 더 많은 데이터를 병렬로 처리해 성능을 높일 수 있어요. 어떤 세그먼트에 대한 연산도 최대 500ms 안에 끝나도록 Druid 세그먼트를 크기 조정하세요. 연산 시간을 모니터링하려면 query/segment/time 메트릭을 사용하세요.
Druid는 세그먼트를 스캔하라는 요청을 내부적으로 우선순위 큐에 저장해요. 어떤 쿼리가 클러스터에 있는 전체 프로세서 수보다 더 많은 세그먼트를 스캔해야 하고, 비슷하게 비싼 여러 쿼리가 동시에 실행 중이라면, 어떤 쿼리도 굶어 죽지(starvation) 않기를 원해요. Druid의 내부 처리 로직은 스캔이 완료되는 즉시 한 쿼리에서 스캔한 세그먼트 세트를 처리하고 자원을 해제해요. 이렇게 해서 다른 쿼리의 두 번째 세그먼트 세트를 스캔할 수 있어요. 세그먼트 연산 시간을 매우 작게 유지함으로써 자원이 계속 해제되고, 서로 다른 쿼리에 속한 세그먼트들이 모두 처리되도록 보장해요.
Druid 쿼리는 선택적으로 query context reference 에 priority 플래그를 설정할 수 있어요. 느릴 것으로 알려진 쿼리(다운로드나 보고서 형태의 쿼리)는 우선순위를 낮추고, 더 인터랙티브한 쿼리는 더 높은 우선순위를 가질 수 있어요.
Broker 프로세스도 특정 티어에 전용으로 할당할 수 있어요. 예를 들어 한 묶음의 Broker 프로세스는 빠른 인터랙티브 쿼리에, 두 번째 묶음의 Broker 프로세스는 느린 보고용 쿼리에 전용으로 쓸 수 있어요. Druid는 또한 다양한 쿼리 파라미터(datasource, interval 등)에 따라 쿼리를 서로 다른 Broker로 라우팅하는 Router 프로세스도 제공해요.
더 알아보기 (Learn more)
- Query context reference — 쿼리 우선순위 등 context 설정을 자세히 알아보세요.
- 다차원 파티셔닝 —
tenant_id기반 파티셔닝에 대해 더 살펴보세요.