멀티-클러스터 쿼리

멀티-클러스터 쿼리 (Multi-Cluster Querying)

멀티-클러스터 쿼리(페더레이션)를 사용해 여러 Pinot 클러스터에 걸쳐 데이터를 조회해요.

출처: 문서

본문

멀티-클러스터 쿼리(페더레이션이라고도 함)는 논리 테이블(logical tables)을 사용해 Apache Pinot 브로커가 여러 Pinot 클러스터에 걸쳐 쿼리를 실행할 수 있게 해요. 다른 클러스터의 물리 테이블을 참조하는 논리 테이블을 만들면, 클러스터에 분산된 데이터를 마치 하나의 통합 테이블인 것처럼 조회할 수 있어요.

개요 (Overview)

멀티-클러스터 쿼리를 사용하면 다음과 같은 일을 할 수 있어요.

  • 여러 클러스터의 물리 테이블을 결합하는 논리 테이블 생성
  • 페더레이션된 논리 테이블을 단일 통합 뷰로 조회
  • multi-stage 쿼리 엔진을 사용해 교차-클러스터 조인 실행
  • 단일 쿼리에서 여러 클러스터의 데이터 집계

중요: 논리 테이블만 멀티-클러스터 페더레이션을 지원해요. 원격 클러스터의 물리 테이블은 직접 조회할 수 없어요 — 반드시 이를 참조하는 논리 테이블을 만들어야 해요.

이 기능은 특히 다음과 같은 경우에 유용해요.

  • 지리적 분산: 서로 다른 지역의 클러스터 데이터 조회
  • 데이터 격리: 서로 다른 데이터 보존 정책이나 보안 경계가 있는 클러스터를 걸쳐 조회
  • 논리 테이블 페더레이션: 서로 다른 클러스터의 물리 테이블을 단일 논리 뷰로 결합

동작 원리 (How It Works)

멀티-클러스터 쿼리는 브로커의 라우팅 기능을 원격 클러스터까지 확장해요.

  1. 브로커 기동: 브로커는 해당 ZooKeeper 인스턴스를 통해 원격 클러스터에 Helix spectator로 연결해요.
  2. 라우팅 테이블 구축: 브로커는 로컬 및 모든 원격 클러스터에 대한 라우팅 테이블을 유지하며 주기적으로 테이블 변경을 확인해요.
  3. 쿼리 실행: 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)

멀티-클러스터 쿼리를 활성화하기 전에:

  1. 모든 클러스터가 브로커 호스트에서 ZooKeeper를 통해 접근 가능해야 함
  2. 브로커와 모든 클러스터의 서버 사이에 네트워크 연결이 존재해야 함
  3. 논리 테이블 페더레이션의 경우 테이블 스키마가 클러스터 간에 호환되어야 함

구성 (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 연결 실패가 표시됨

해결책:

  1. ZooKeeper 주소가 올바른지 확인: pinot.remote.zk.server.<clusterName>
  2. 네트워크 연결 테스트: nc -zv <zk-host> <zk-port>
  3. ZooKeeper가 실행 중이고 접근 가능한지 확인
  4. 연결을 차단하는 방화벽 규칙이 없는지 확인

쿼리가 원격 클러스터에서 데이터를 반환하지 않음

증상: 쿼리 결과가 로컬 데이터만 포함된 것 같음

해결책:

  1. 쿼리에 enableMultiClusterRouting=true가 설정되었는지 확인
  2. 브로커 로그에서 원격 클러스터 연결 상태 확인
  3. 테이블이 원격 클러스터에 존재하는지 확인
  4. 논리 테이블의 경우 multiCluster: true가 올바르게 설정되었는지 확인

쿼리 응답의 오류 코드 510

증상: 쿼리 응답에 오류 코드 510 예외가 포함됨

해결책: 이는 원격 클러스터를 사용할 수 없음을 나타내요. 다음을 확인하세요.

  1. 원격 클러스터 상태 및 ZooKeeper 상태
  2. 브로커에서 원격 ZooKeeper로의 네트워크 연결
  3. 일시적이면 결과가 불완전할 수 있지만 쿼리는 성공함

높은 쿼리 지연

증상: 멀티-클러스터 쿼리가 단일-클러스터보다 훨씬 느림

해결책:

  1. 원격 클러스터 서버(ZK뿐만 아니라)로의 네트워크 지연 확인
  2. EXPLAIN PLAN FOR를 사용해 쿼리 실행 이해
  3. 데이터 지역성 최적화 고려

더 알아보기 (Learn more)