Coordinator 서비스
Coordinator 서비스 (Coordinator service)
Coordinator 서비스는 주로 segment 관리와 분배를 담당해요. 구성에 따라 Historical 서비스에 segment를 로드하거나 drop하도록 통신해요. 새 segment 로드, 오래된 segment drop, segment 복제, 그리고 지역 간 segment 밸런싱을 처리해요.
출처: 문서
본문
Coordinator 서비스는 주로 segment 관리와 분배를 담당해요. 더 구체적으로, Coordinator 서비스는 구성에 따라 segment를 로드하거나 drop하도록 Historical 서비스에 통신해요. Coordinator는 새 segment 로드, 오래된 segment drop, segment가 적절한(구성된) 횟수만큼 "복제"(즉 여러 다른 Historical 노드에 로드)되도록 보장, 그리고 Historical 노드가 고르게 로드되도록 노드 간 segment 이동("balancing")을 담당해요.
Coordinator는 주기적으로 duty를 실행하며 각 실행 사이의 시간은 구성 가능한 파라미터예요. 각 실행에서 Coordinator는 적절한 조치를 결정하기 전에 클러스터의 현재 상태를 평가해요.
Broker와 Historical 서비스와 유사하게 Coordinator는 현재 클러스터 정보를 위해 ZooKeeper 클러스터에 연결을 유지해요. Coordinator는 "used" segment(즉 클러스터에 로드되어야 하는 segment)와 로딩 규칙에 대한 정보를 포함한 데이터베이스에도 연결을 유지해요.
할당되지 않은 segment가 Historical 서비스에 서비스되기 전에, 각 tier의 Historical 서비스는 먼저 용량 기준으로 정렬되며 용량이 가장 적은 서버가 가장 높은 우선순위를 가져요. 할당되지 않은 segment는 서비스 간 균형 수준을 유지하기 위해 항상 용량이 가장 적은 서비스에 할당돼요. Coordinator는 새 segment를 할당할 때 Historical 서비스와 직접 통신하지 않아요. 대신 Historical 서비스의 load queue 경로 아래에 새 segment에 대한 임시 정보를 만들어요. 이 요청이 보이면 Historical 서비스는 segment를 로드하고 서비스를 시작해요.
설정 (Configuration)
Apache Druid Coordinator 서비스 설정은 Coordinator configuration을 참고하세요.
Coordinator 서비스에 대한 기본 튜닝 지침은 Basic cluster tuning을 참고하세요.
HTTP 엔드포인트
Coordinator가 지원하는 API 엔드포인트 목록은 Service status API reference를 참고하세요.
실행 (Running)
org.apache.druid.cli.Main server coordinator
규칙 (Rules)
규칙 집합에 따라 segment를 클러스터에서 자동으로 로드하고 drop할 수 있어요. 규칙에 대한 자세한 내용은 Rule Configuration을 참고하세요.
Overshadow된 segment 정리
각 실행에서 Coordinator는 데이터베이스의 used segment 집합을 클러스터의 일부 Historical 노드가 서비스하는 segment와 비교해요. Coordinator는 사용되지 않는 segment나 데이터베이스에서 제거된 segment를 내리도록 Historical 노드에 요청을 보내요.
Overshadow된 segment(버전이 너무 오래되고 데이터가 더 새 segment로 교체된 segment)는 unused로 표시돼요. 다음 Coordinator 실행에서 클러스터의 Historical 노드에서 내려져요.
Non-overshadowed eternity tombstone segment 정리
각 실행에서 Coordinator는 각 데이터소스에 대해 필요 없는 eternity tombstone segment를 결정하고 정리해요. 이 segment는 다음 기준을 모두 충족해야 해요:
-INF에서 시작하거나INF에서 끝나는 tombstone segment(예: interval이-146136543-09-08T08:23:32.096Z/2000-01-01이거나2020-01-01/146140482-04-24T15:36:27.903Z이거나-146136543-09-08T08:23:32.096Z/146140482-04-24T15:36:27.903Z인 tombstone)- 어떤 overshadow된 segment와도 겹치지 않는 segment
- core 파티션이 0개인 segment
Segment 가용성
Historical 서비스가 어떤 이유로든 재시작되거나 이용 불가능해지면, Coordinator는 서비스가 사라진 것을 알아차리고 그 서비스가 서비스하던 모든 segment를 drop된 것으로 취급해요. 그런 다음 segment는 클러스터의 다른 Historical 서비스에 재할당돼요. 하지만 drop된 각 segment가 즉시 잊히지는 않아요. 대신, 연관된 수명(lifetime)과 함께 모든 drop된 segment를 저장하는 과도기적 데이터 구조가 있어요. 수명은 Coordinator가 drop된 segment를 재할당하지 않을 기간을 나타내요. 따라서 Historical 서비스가 짧은 시간 내에 이용 불가능해졌다가 다시 이용 가능해지면, Historical 서비스는 segment가 클러스터 전체에 재할당되지 않은 채 자신의 캐시에서 segment를 시작·서비스해요.
tier 내 segment 밸런싱
segment가 Historical 서비스 전체에 고르게 분산되면 Druid 쿼리가 최적으로 수행돼요. 이상적인 분산은 모든 Historical이 쿼리 부하에 동등하게 참여해 시스템의 핫스팟을 피하도록 보장해요. 어느 정도는 클러스터에 segment의 복제본을 여러 개 유지하면 달성할 수 있어요.
하지만 Historical이 여러 개 있는 tier(또는 복제 팩터가 낮은 tier)에서는 segment 복제만으로는 균형을 달성하기에 충분하지 않아요.
따라서 Coordinator는 tier의 각 Historical에 존재하는 segment 집합을 지속적으로 모니터링하고, 균형을 유지하기 위해 한 Historical에서 다른 Historical로 이동할 수 있는 segment를 식별하기 위해 다음 전략 중 하나를 사용해요.
cost(기본값): tier의 주어진 segment에 대해 이 전략은 해당 segment를 배치하는 "비용"이 최소인 서버를 선택해요. 비용은 segment의 데이터 interval과 후보 서버에 이미 존재하는 모든 segment의 데이터 interval의 함수예요. 본질적으로 이 전략은 인접하거나 겹치는 데이터 interval을 가진 segment를 같은 서버에 배치하는 것을 피하려고 해요. 인접 interval segment는 쿼리에서 함께 사용될 가능성이 높고, 같은 서버에 배치하면 Historical의 CPU 사용량이 편향될 수 있다는 전제에 기반해요.diskNormalized:cost전략의 파생형으로, 서버에 segment를 배치하는 비용을 서버의 디스크 사용률로 가중치를 준 전략이에요. 이 전략에는 알려진 문제가 있어 프로덕션 클러스터에는 권장되지 않아요.random: segment를 서버 전체에 무작위로 분산해요. 실험적 전략이며 프로덕션 클러스터에는 권장되지 않아요.
위 모든 전략은 사용 가능한 디스크 공간이 가장 적은 Historical에서 segment를 옮기는 것을 우선시해요.
자동 컴팩션
Coordinator는 자동 컴팩션 시스템을 관리해요.
각 실행에서 Coordinator는 작은 segment를 병합하거나 큰 segment를 분할해 segment를 컴팩션해요. segment 크기가 최적화되지 않아 쿼리 성능이 저하될 수 있을 때 유용해요.
자세한 내용은 Segment size optimization을 참고하세요.
Coordinator는 먼저 segment search policy에 기반해 컴팩션할 segment를 찾아요. 일부 segment를 찾으면 컴팩션할 compaction task를 발행해요.
실행 중인 컴팩션 task의 최대 수는 min(sum of worker capacity * slotRatio, maxSlots)이에요.
min(sum of worker capacity * slotRatio, maxSlots) = 0이어도, 데이터소스에 컴팩션이 활성화되어 있으면 컴팩션 task는 항상 최소 하나는 제출돼요.
자동 컴팩션을 활성화하고 구성하려면 Automatic compaction configuration API와 Automatic compaction configuration을 참고하세요.
컴팩션 task는 다음 이유로 실패할 수 있어요:
- 컴팩션 task의 입력 segment가 시작 전에 제거되거나 overshadow되면 그 컴팩션 task는 즉시 실패해요.
- 더 높은 우선순위 task가 컴팩션 task의 interval과 겹치는 interval에 대해 time chunk lock을 획득하면 컴팩션 task가 실패해요.
컴팩션 task가 실패하면, Coordinator는 실패한 task의 interval의 segment를 다시 확인하고 다음 실행에서 또 다른 컴팩션 task를 발행해요.
참고로 Compacting Segments Coordinator Duty는 Indexing Service Duties 그룹의 일부로 자동 활성화되어 실행돼요. 하지만 Compacting Segments Coordinator Duty는 별도의 Coordinator duty 그룹으로 격리 실행되도록 구성할 수 있어요. 이렇게 하면 다른 Indexing Service Duties의 주기에 영향을 주지 않고 Compacting Segments Coordinator Duty의 주기를 변경할 수 있어요. 다음 속성을 설정하면 됩니다. 자세한 내용은 custom pluggable Coordinator Duty를 참고하세요.
druid.coordinator.dutyGroups=[<SOME_GROUP_NAME>]
druid.coordinator.<SOME_GROUP_NAME>.duties=["compactSegments"]
druid.coordinator.<SOME_GROUP_NAME>.period=<PERIOD_TO_RUN_COMPACTING_SEGMENTS_DUTY>
자동 컴팩션의 segment search policy
Coordinator가 실행될 때마다 이 policy는 시간 chunk를 최신에서 오래된 순서로 조회하고 그 시간 chunk의 segment가 컴팩션을 필요로 하는지 확인해요.
다음 조건이 모두 충족되면 segment 집합은 컴팩션이 필요해요:
- 시간 chunk의 segment 총 크기가 구성된
inputSegmentSizeBytes보다 작거나 같음 - segment가 아직 한 번도 컴팩션되지 않았거나, 마지막 컴팩션 이후 컴팩션 spec이 업데이트됨:
maxTotalRows또는indexSpec
예시를 들어 자세히 설명할게요. 아래처럼 foo와 bar 두 데이터소스가 있다고 가정해 봐요:
foo
foo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSIONfoo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSION_1foo_2017-09-01T00:00:00.000Z_2017-10-01T00:00:00.000Z_VERSION
bar
bar_2017-10-01T00:00:00.000Z_2017-11-01T00:00:00.000Z_VERSIONbar_2017-10-01T00:00:00.000Z_2017-11-01T00:00:00.000Z_VERSION_1
각 segment가 10MB이고 아직 컴팩션되지 않았다고 가정하면, 이 policy는 먼저 2017-11-01T00:00:00.000Z/2017-12-01T00:00:00.000Z가 가장 최근 시간 chunk이므로 foo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSION과 foo_2017-11-01T00:00:00.000Z_2017-12-01T00:00:00.000Z_VERSION_1 두 segment를 함께 컴팩션하도록 반환해요.
Coordinator에게 컴팩션용 task 슬롯이 충분하면 이 policy는 계속해서 다음 segment를 검색하고 bar_2017-10-01T00:00:00.000Z_2017-11-01T00:00:00.000Z_VERSION과 bar_2017-10-01T00:00:00.000Z_2017-11-01T00:00:00.000Z_VERSION_1을 반환해요.
마지막으로, 2017-09-01T00:00:00.000Z/2017-10-01T00:00:00.000Z 시간 chunk에 segment가 하나뿐이어도 foo_2017-09-01T00:00:00.000Z_2017-10-01T00:00:00.000Z_VERSION이 선택돼요.
검색 시작점은 skipOffsetFromLatest를 설정해 변경할 수 있어요. 이 값이 설정되면 이 policy는 (가장 최근 segment의 끝 시간 - skipOffsetFromLatest)의 시간 chunk에 들어가는 segment를 무시해요. 이는 컴팩션 task와 realtime task 사이의 충돌을 피하기 위해서예요.
realtime task는 기본적으로 컴팩션 task보다 높은 우선순위를 가진다는 점에 유의하세요. realtime task는 interval이 겹치면 컴팩션 task의 lock을 회수해서 컴팩션 task를 종료시켜요.
자세한 내용은 Avoid conflicts with ingestion을 참고하세요.
info
이 policy는 현재 같은 interval을 가진 작은 segment가 많고 그 총 크기가 inputSegmentSizeBytes를 초과하는 상황을 처리할 수 없어요. 그런 segment를 찾으면 단순히 건너뛰어요.
FAQ
클라이언트가 Coordinator 서비스에 접촉하나요?
Coordinator는 쿼리에 관여하지 않아요.
Historical 서비스는 Coordinator 서비스에 직접 접촉하지 않아요. Coordinator는 ZooKeeper를 통해 Historical 서비스에 데이터를 로드/drop하라고 알려주지만, Historical 서비스는 Coordinator의 존재를 전혀 알지 못해요.
Broker도 Coordinator에 접촉하지 않아요. Broker는 Historical 서비스가 ZooKeeper를 통해 노출하는 메타데이터를 기반으로 데이터 토폴로지를 이해하며 Coordinator의 존재를 전혀 알지 못해요.
Coordinator 서비스가 다른 서비스보다 먼저 혹은 나중에 시작되는 것이 중요해요?
아니요. Coordinator가 시작되지 않으면 새 segment가 클러스터에 로드되지 않고 오래된 segment가 drop되지 않아요. 하지만 Coordinator 서비스는 언제든 시작할 수 있고, 구성 가능한 지연 후 Coordinator task를 실행하기 시작해요.
이는 또한 작동 중인 클러스터가 있고 모든 Coordinator가 죽으면, 클러스터가 계속 기능하지만 데이터 토폴로지에 어떤 변경도 겪지 않는다는 뜻이에요.
더 알아보기 (Learn more)
- Rule Configuration — segment 자동 로드/drop 규칙을 알아봐요.
- Automatic compaction — Coordinator가 관리하는 자동 컴팩션을 살펴봐요.
- Coordinator configuration — Coordinator 서비스 설정을 자세히 알아봐요.