멀티-클러스터 쿼리
멀티-클러스터 쿼리 (Multi-Cluster Querying)
멀티-클러스터 쿼리(페더레이션)를 사용해 여러 Pinot 클러스터에 걸쳐 데이터를 조회해요.
출처: 문서
본문
멀티-클러스터 쿼리(페더레이션이라고도 함)는 논리 테이블(logical tables)을 사용해 Apache Pinot 브로커가 여러 Pinot 클러스터에 걸쳐 쿼리를 실행할 수 있게 해요. 다른 클러스터의 물리 테이블을 참조하는 논리 테이블을 만들면, 클러스터에 분산된 데이터를 마치 하나의 통합 테이블인 것처럼 조회할 수 있어요.
개요 (Overview)
멀티-클러스터 쿼리를 사용하면 다음과 같은 일을 할 수 있어요.
- 여러 클러스터의 물리 테이블을 결합하는 논리 테이블 생성
- 페더레이션된 논리 테이블을 단일 통합 뷰로 조회
- multi-stage 쿼리 엔진을 사용해 교차-클러스터 조인 실행
- 단일 쿼리에서 여러 클러스터의 데이터 집계
중요: 논리 테이블만 멀티-클러스터 페더레이션을 지원해요. 원격 클러스터의 물리 테이블은 직접 조회할 수 없어요 — 반드시 이를 참조하는 논리 테이블을 만들어야 해요.
이 기능은 특히 다음과 같은 경우에 유용해요.
- 지리적 분산: 서로 다른 지역의 클러스터 데이터 조회
- 데이터 격리: 서로 다른 데이터 보존 정책이나 보안 경계가 있는 클러스터를 걸쳐 조회
- 논리 테이블 페더레이션: 서로 다른 클러스터의 물리 테이블을 단일 논리 뷰로 결합
동작 원리 (How It Works)
멀티-클러스터 쿼리는 브로커의 라우팅 기능을 원격 클러스터까지 확장해요.
- 브로커 기동: 브로커는 해당 ZooKeeper 인스턴스를 통해 원격 클러스터에 Helix spectator로 연결해요.
- 라우팅 테이블 구축: 브로커는 로컬 및 모든 원격 클러스터에 대한 라우팅 테이블을 유지하며 주기적으로 테이블 변경을 확인해요.
- 쿼리 실행:
enableMultiClusterRouting=true가 설정되면:- 브로커는 모든 클러스터에 대해 라우팅 매니저를 조회함
- 로컬과 원격 클러스터에 걸쳐 라우트를 결합함
- 쿼리를 모든 적용 가능한 클러스터의 서버로 분산함
- 클라이언트에 반환하기 전에 결과를 병합함
Client Application
│ SQL query
▼
Multi-Cluster Broker (federation)
Local ZooKeeper Remote ZooKeeper(s)
│ │
└──────────┬─────────┘
│ combined routes
Primary Cluster Remote Cluster(s)
│ scatter queries / gather results
Broker merges and returns response
사전 요구 사항 (Prerequisites)
멀티-클러스터 쿼리를 활성화하기 전에:
- 모든 클러스터가 브로커 호스트에서 ZooKeeper를 통해 접근 가능해야 함
- 브로커와 모든 클러스터의 서버 사이에 네트워크 연결이 존재해야 함
- 논리 테이블 페더레이션의 경우 테이블 스키마가 클러스터 간에 호환되어야 함
구성 (Configuration)
브로커 구성
멀티-클러스터 쿼리를 활성화하려면 브로커가 MultiClusterHelixBrokerStarter를 사용하도록 구성하고 원격 클러스터 연결을 지정하세요.
구성 속성:
pinot.remote.cluster.names: 원격 클러스터 이름의 쉼표 구분 목록pinot.remote.zk.server.<clusterName>: 각 원격 클러스터의 ZooKeeper 주소
예시 구성:
# Local cluster configuration
pinot.cluster.name=PrimaryCluster
pinot.zk.server=localhost:2181
# Remote cluster configuration
pinot.remote.cluster.names=SecondaryCluster,TertiaryCluster
pinot.remote.zk.server.SecondaryCluster=secondary-zk:2181
pinot.remote.zk.server.TertiaryCluster=tertiary-zk:2181
브로커 시작 클래스
구성 파일에 멀티-클러스터 브로커 스타터를 추가하세요.
pinot.broker.startable.class=org.apache.pinot.broker.broker.helix.MultiClusterHelixBrokerStarter
pinot.broker.startable.class속성은 필수예요. 이것이 없으면 브로커는 단일-클러스터 쿼리만 지원하는 기본HelixBrokerStarter를 사용해요.
브로커 시작
구성 파일로 브로커를 시작하세요.
bin/pinot-admin.sh StartBroker \
-configFileName /path/to/broker.conf
또는 빠른 테스트를 위해 구성 오버라이드를 사용하세요.
bin/pinot-admin.sh StartBroker \
-zkAddress localhost:2181 \
-clusterName PrimaryCluster \
-configOverrides "pinot.remote.cluster.names=SecondaryCluster,pinot.remote.zk.server.SecondaryCluster=secondary-zk:2181,pinot.broker.startable.class=org.apache.pinot.broker.broker.helix.MultiClusterHelixBrokerStarter"
브로커 시작 확인
원격 클러스터 연결 성공 여부를 브로커 로그에서 확인하세요.
[multi-cluster] Starting multi-cluster broker
[multi-cluster] Connected to remote cluster 'SecondaryCluster' at ZK: secondary-zk:2181
[multi-cluster] Multi-cluster broker started successfully
원격 클러스터 연결에 실패하면 경고가 표시되지만 브로커는 여전히 시작돼요.
[multi-cluster] Failed to connect to cluster 'TertiaryCluster'
[multi-cluster] The following clusters are unavailable: [TertiaryCluster]
멀티-클러스터 쿼리 실행
멀티-클러스터 라우팅은 각 쿼리에 대해 enableMultiClusterRouting 쿼리 옵션으로 명시적으로 활성화해야 해요.
⚠️
enableMultiClusterRouting=true가 없으면 브로커가 멀티-클러스터로 구성되어 있어도 쿼리는 로컬 클러스터에 대해서만 실행돼요.
SET 문 사용
SET enableMultiClusterRouting=true;
SELECT COUNT(*) FROM unified_sales
Multi-Stage 엔진으로 교차-클러스터 조인
멀티-클러스터 쿼리는 조인을 포함한 복잡한 쿼리에 대해 multi-stage 쿼리 엔진과 함께 동작해요.
SET enableMultiClusterRouting=true;
SET useMultistageEngine=true;
SELECT
o.order_id,
o.customer_name,
p.product_name,
o.quantity
FROM unified_orders o
JOIN unified_products p ON o.product_id = p.product_id
WHERE o.order_date > '2024-01-01'
LIMIT 100
조인의 각 테이블은 여전히 논리 테이블이어야 해요. 멀티-클러스터 라우팅은 물리 테이블에 대한 직접 쿼리를 거부해요.
멀티-클러스터가 있는 논리 테이블
⚠️ 논리 테이블만 클러스터 간에 페더레이션할 수 있어요. 물리 테이블은 클러스터 간에 직접 조회할 수 없어요. 여러 클러스터의 데이터를 조회하려면 각 클러스터의 물리 테이블을 참조하는 논리 테이블을 만들어야 해요.
멀티-클러스터 쿼리는 논리 테이블과 통합되어, 서로 다른 클러스터의 물리 테이블을 결합할 수 있어요.
페더레이션된 논리 테이블 생성
1단계: 각 클러스터에 물리 테이블이 존재하는지 확인하세요.
- PrimaryCluster(로컬)의
sales_east_OFFLINE - SecondaryCluster(원격)의
sales_west_OFFLINE
2단계: 논리 테이블 구성을 생성하세요.
{
"tableName": "unified_sales",
"physicalTableConfigMap": {
"sales_east_OFFLINE": {
"multiCluster": false
},
"sales_west_OFFLINE": {
"multiCluster": true
}
},
"brokerTenant": "DefaultTenant",
"refOfflineTableName": "sales_east_OFFLINE"
}
| Field | Description |
|---|---|
tableName |
논리 테이블의 이름 |
physicalTableConfigMap |
물리 테이블 이름을 해당 구성으로 매핑 |
multiCluster |
원격 클러스터의 테이블은 true, 로컬 테이블은 false로 설정 |
refOfflineTableName |
스키마 및 구성 상속을 위한 참조 테이블 |
3단계: Controller API를 통해 논리 테이블을 생성하세요.
curl -X POST 'http://localhost:9000/logicalTables' \
-H 'Content-Type: application/json' \
-d @unified_sales_logical_table.json
4단계: 논리 테이블을 조회하세요.
SET enableMultiClusterRouting=true;
SELECT region, SUM(revenue)
FROM unified_sales
GROUP BY region
논리 테이블은 각 클러스터의 컨트롤러에, 그 클러스터의 관점에서 어떤 테이블이 로컬인지 원격인지를 나타내는 적절한
multiCluster플래그와 함께 생성되어야 해요.
쿼리 동작 (Query Behavior)
사용 불가능한 클러스터
원격 클러스터를 사용할 수 없으면(ZooKeeper에 연결할 수 없으면) 브로커는:
- 사용 가능한 클러스터를 사용해 쿼리 처리를 계속함
- 사용할 수 없는 클러스터를 나타내는 경고를 쿼리 응답에 추가함
- 데이터가 사용 불가능한 클러스터에만 존재하면 쿼리 결과가 불완전할 수 있음
사용 불가능한 클러스터가 있는 예시 응답:
{
"resultTable": { ... },
"exceptions": [
{
"errorCode": 510,
"message": "Remote cluster 'SecondaryCluster' is not connected. Query results may be incomplete."
}
]
}
오류 코드 510(RemoteClusterUnavailable)은 쿼리 결과가 불완전할 수 있음을 나타내요.
구성 참조 (Configuration Reference)
브로커 속성
| Property | Description | Required |
|---|---|---|
pinot.remote.cluster.names |
원격 클러스터 이름의 쉼표 구분 목록 | Yes |
pinot.remote.zk.server.<clusterName> |
지정된 원격 클러스터의 ZooKeeper 주소 | Yes (per cluster) |
pinot.broker.startable.class |
org.apache.pinot.broker.broker.helix.MultiClusterHelixBrokerStarter여야 함 |
Yes |
쿼리 옵션
| Option | Type | Default | Description |
|---|---|---|---|
enableMultiClusterRouting |
boolean | false |
구성된 모든 클러스터에 걸쳐 쿼리 활성화 |
성능 고려 사항
| Factor | Impact | Recommendation |
|---|---|---|
| 네트워크 지연 | 교차-클러스터 쿼리가 네트워크 RTT를 추가함 | 모든 클러스터에 낮은 지연인 브로커 배치 |
| 쿼리 타임아웃 | 타임아웃이 전체 페더레이션 쿼리에 적용됨 | 최악의 클러스터 지연을 고려해 타임아웃 설정 |
| 라우팅 테이블 크기 | 원격 테이블에 따라 브로커 메모리 증가 | 브로커 힙 사용량 모니터링 |
| ZK 연결 | 브로커가 모든 ZK에 spectator 연결을 유지함 | ZK가 추가 연결을 처리할 수 있는지 확인 |
제한 사항 (Limitations)
- 논리 테이블만: 논리 테이블만 클러스터 간에 페더레이션할 수 있음; 물리 테이블은 원격 클러스터에서 직접 조회할 수 없음
- 교차-클러스터 수집 없음: 멀티-클러스터 쿼리는 읽기 전용; 데이터 수집은 클러스터별로 이루어짐
- 스키마 호환성: 논리 테이블은 물리 테이블 간에 호환 스키마가 필요
- 단일 쿼리 타임아웃: 클러스터별 타임아웃을 설정할 수 없음
- ZK 접근성: 모든 원격 ZooKeeper가 브로커 호스트에서 도달 가능해야 함
문제 해결 (Troubleshooting)
브로커가 시작하지 않거나 원격 클러스터에 연결하지 못함
증상: 브로커 로그에 원격 ZooKeeper 연결 실패가 표시됨
해결책:
- ZooKeeper 주소가 올바른지 확인:
pinot.remote.zk.server.<clusterName> - 네트워크 연결 테스트:
nc -zv <zk-host> <zk-port> - ZooKeeper가 실행 중이고 접근 가능한지 확인
- 연결을 차단하는 방화벽 규칙이 없는지 확인
쿼리가 원격 클러스터에서 데이터를 반환하지 않음
증상: 쿼리 결과가 로컬 데이터만 포함된 것 같음
해결책:
- 쿼리에
enableMultiClusterRouting=true가 설정되었는지 확인 - 브로커 로그에서 원격 클러스터 연결 상태 확인
- 테이블이 원격 클러스터에 존재하는지 확인
- 논리 테이블의 경우
multiCluster: true가 올바르게 설정되었는지 확인
쿼리 응답의 오류 코드 510
증상: 쿼리 응답에 오류 코드 510 예외가 포함됨
해결책: 이는 원격 클러스터를 사용할 수 없음을 나타내요. 다음을 확인하세요.
- 원격 클러스터 상태 및 ZooKeeper 상태
- 브로커에서 원격 ZooKeeper로의 네트워크 연결
- 일시적이면 결과가 불완전할 수 있지만 쿼리는 성공함
높은 쿼리 지연
증상: 멀티-클러스터 쿼리가 단일-클러스터보다 훨씬 느림
해결책:
- 원격 클러스터 서버(ZK뿐만 아니라)로의 네트워크 지연 확인
EXPLAIN PLAN FOR를 사용해 쿼리 실행 이해- 데이터 지역성 최적화 고려
관련 문서 (Related Documentation)
- Query Options -
enableMultiClusterRouting을 포함한 쿼리 옵션 전체 목록 - Multi-Stage Query Engine - 클러스터 간 고급 쿼리 실행
- Tables - 논리 테이블을 포함한 테이블 유형과 개념
- Broker Configuration - 브로커 구성 참조