Apache Pinot 1.5: 멀티클러스터 페더레이션과 Multi-Stage 쿼리 엔진으로 리얼타임 OLAP의 운영 경계를 다시 그은 릴리스
왜 Pinot이고 왜 1.5인가
Apache Pinot은 LinkedIn에서 시작한 사용자 대면 리얼타임 OLAP 데이터베이스다. 분석 쿼리를 초 단위가 아니라 밀리초 단위로 처리해야 하는 시나리오, 즉 "지금 이 페이지를 보는 사람의 최근 30일 행동 요약"이나 "광고 캠페인의 실시간 클릭률"처럼 수억 건 레코드를 수백 밀리초 안에 돌려줘야 하는 환경을 위해 설계됐다.
기존 접근법의 한계는 명확했다.
- OLTP DB (MySQL, PostgreSQL): 집계·스캔이 느리고 동시 분석 쿼리가 운영 쓰기 성능을 잠식한다.
- 범용 OLAP (Hive, Presto/Trino): 지연 시간이 수 초에서 수십 초, 사용자 대면 SLA를 맞추기 어렵다.
- 캐시 (Redis): 집계 쿼리 조합이 폭발하면 캐시 전략 자체가 유지되지 않는다.
Pinot이 이 틈새를 채운다. 2026년 4월 15일 출시된 Pinot 1.5.0은 운영자가 주목할 세 가지 구조적 변화를 담고 있다: 멀티클러스터 페더레이션 라우팅, MSE 쿼리 엔진 성숙, Upsert 운영 개선. 그리고 Kafka 4.x KRaft 지원으로 ZooKeeper 의존 고리를 하나 더 끊었다.
Pinot 아키텍처 기본
Pinot 클러스터는 네 종류의 프로세스로 구성된다.
- Controller: 클러스터 메타데이터 관리, 세그먼트 할당, 테이블 설정 소유
- Broker: 쿼리를 받아 적절한 서버에 분산(scatter), 결과를 모아(gather) 반환
- Server: 세그먼트를 저장하고 쿼리를 실행. 실시간 서버(스트림 소비)와 오프라인 서버(배치 세그먼트 호스팅)로 분리됨
- Minion: 세그먼트 병합·최적화·퍼지 같은 백그라운드 작업 수행
클러스터 조정은 Apache Helix와 ZooKeeper가 담당한다. Helix가 원하는 상태(서버 수, 세그먼트 할당 등)를 ZooKeeper에 유지하고, 각 컴포넌트가 이 상태를 지켜보며 자신의 역할을 수행한다.
세그먼트 단위로 데이터를 관리한다는 점이 핵심이다. 배치 수집은 세그먼트 파일을 만들어 딥스토어에 올리고 Controller에 알리는 방식이고, 실시간 수집은 서버가 Kafka를 직접 소비하면서 메모리에서 세그먼트를 만든다. 이 세그먼트가 커밋(flushed)되면 스토리지에 쓰이고 오프라인 세그먼트와 동일하게 관리된다.
핵심 변화 1: 멀티클러스터 페더레이션 라우팅
Pinot 1.5의 가장 구조적인 변화다. 기존에는 하나의 Broker가 하나의 Pinot 클러스터 안의 서버들에게 쿼리를 분산했다. 조직이 여러 Pinot 클러스터를 운영한다면—예컨대 지역별·서비스별로 독립된 클러스터—쿼리 시에 어느 클러스터에 붙을지를 애플리케이션이 알고 있어야 했다.
1.5에서 Federation Broker가 이 책임을 가져간다. 단일 브로커 엔드포인트에 쿼리를 보내면, 브로커가 여러 Pinot 클러스터로 라우팅하고 결과를 합쳐서 반환한다.
운영 모델 변화
이 기능은 Logical Table 위에서만 동작한다. 물리 테이블(physical table)에 대한 직접 멀티클러스터 라우팅은 의도적으로 막혀 있다.
Logical Table은 Pinot 1.4에서 도입된 개념으로, 여러 물리 테이블을 하나의 논리 테이블로 묶는 레이어다. 1.5에서는 이 논리 테이블이 서로 다른 클러스터에 있는 물리 테이블을 묶을 수 있게 됐다.
이것이 열어주는 운영 시나리오는 구체적이다.
- 지역 분리: 한국, 동남아, 일본 클러스터를 각자 독립 운영하면서 글로벌 집계는 Federation Broker로
- 테넌트 분리: 고객사별 클러스터를 독립 운영하면서 내부 리포팅은 통합 뷰로
- 부하 분리: 실시간 데이터와 역사 데이터를 다른 클러스터에 두고 쿼리는 하나의 엔드포인트로
SSE(Single-Stage Engine) 쿼리와 MSE(Multi-Stage Engine) 쿼리 모두 멀티클러스터 라우팅을 지원한다.
제약
- Logical Table을 통해서만 라우팅 가능. 물리 테이블 직접 라우팅 불가
- Federation Broker 설정에
MultiClusterHelixBrokerStarter사용 필요 - 현재는 읽기 전용 라우팅. 쓰기는 각 클러스터에 개별 수집
핵심 변화 2: Multi-Stage Query Engine(MSE) 성숙
Pinot의 MSE는 분산 조인, 윈도 함수, 서브쿼리 같은 복잡한 SQL을 지원하기 위해 만들어진 실행 엔진이다. 기존 SSE(Single-Stage Engine)는 단순 집계에 특화되어 있어 조인이 제한적이었다.
1.5에서 MSE에 추가된 것들:
UNNEST 지원
UNNEST 함수로 배열·중첩 컬럼을 행으로 전개할 수 있게 됐다. Pinot에는 JSON이나 배열 컬럼에 이벤트 데이터를 통째로 저장하는 패턴이 흔한데, 이를 쿼리 시점에 펼쳐야 하는 경우 지금까지는 클라이언트에서 처리해야 했다.
-- 예: 사용자당 클릭한 상품 목록을 행으로 전개
SELECT user_id, item
FROM user_events, UNNEST(clicked_items) AS t(item)
WHERE event_date = '2026-07-20'Join 강화와 집계 재작성
이너 조인, 외부 조인의 실행 안정성이 향상됐다. 옵티마이저가 집계 연산을 더 효율적인 형태로 재작성(aggregation rewrite)하는 경우가 늘었다.
쿼리 리소스 격리(Query Resource Isolation)
쿼리별로 메모리 한도와 실행 우선순위를 설정할 수 있게 됐다. 특정 대쿼리가 서버 메모리를 독점하는 문제를 제어하는 수단이다.
Upsert 운영 개선
Pinot의 Upsert는 기존 레코드를 새 레코드로 갱신하는 기능이다. 리얼타임 집계에 특화된 Pinot에 "갱신"이 필요한 이유는 이벤트 수정·삭제·중복 제거 같은 실운영 요구사항 때문이다.
1.5에서 Upsert에 두 가지 중요한 변화가 있다.
오프라인 테이블 지원
이전까지 Upsert는 리얼타임 테이블에서만 동작했다. 1.5부터는 오프라인 테이블(배치 수집 테이블)에서도 Upsert가 가능하다.
이것이 열어주는 운영 시나리오: 기존에 잘못 수집된 배치 데이터를 수정하거나, 배치로 들어온 레코드를 기준으로 최신 상태를 유지하는 워크로드.
commit-time compaction과 xxhash 압축
Upsert를 쓰면 같은 primaryKey의 여러 버전이 다른 세그먼트에 분산된다. 쿼리 시에 이 버전들을 비교해 최신 값을 선택하는 비용이 누적된다.
Commit-time compaction은 세그먼트가 커밋될 때 중복 레코드를 정리해서 이 비용을 미리 줄인다. xxhash 기반 레코드 해시는 중복 탐지 속도를 높인다.
Kafka 4.x KRaft 지원
Pinot 1.5는 새 pinot-kafka-4.0 모듈을 추가했다. Kafka 4.1.1 클라이언트 기반이며, KRaft 모드를 완전히 지원한다. 이는 Pinot 수집 경로에서 Kafka ZooKeeper 의존성이 사라진다는 뜻이다.
실무적으로 Kafka 클러스터를 KRaft로 이미 마이그레이션했거나 마이그레이션 계획이 있다면, Pinot 수집 쪽도 같이 업그레이드해야 한다. 기존 Kafka 3.x 연결은 이전 모듈로 계속 동작한다.
추가로 테이블이 특정 파티션만 소비할 수 있게 됐다. 하나의 Kafka 토픽을 여러 Pinot 테이블이 나눠 담당하는 분할 수집 패턴이 가능해진다.
새 인덱스 타입
1.5에서 추가된 인덱스 타입:
| 인덱스 | 용도 |
|---|---|
| N-gram 인덱스 | 부분 문자열 검색 성능 개선 |
| IFST(Inverted Finite State Transducer) 인덱스 | 정규식·와일드카드 검색 최적화 |
| Combined Lucene 인덱스 | 텍스트·숫자 혼합 검색 단일 인덱스로 통합 |
Pinot을 도입할 때 판단 기준
Pinot은 강력하지만 도입 기준을 먼저 명확히 해야 한다.
Pinot이 맞는 경우
- 쿼리 지연이 수백 밀리초 SLA 이하여야 하는 사용자 대면 분석
- 수억~수십억 건 레코드를 실시간으로 집계해야 하는 경우
- Kafka, Pulsar 등 스트리밍 소스에서 실시간으로 수집되는 데이터
- 고정된 쿼리 패턴에 특화된 인덱스 전략이 가능한 경우
Pinot이 맞지 않는 경우
- 복잡한 조인이 필요한 임시(ad-hoc) 분석: Trino/DuckDB 쪽이 적합
- 완전한 ACID 트랜잭션이 필요한 OLTP 워크로드
- 저지연보다 비용이 우선인 내부 배치 분석
1.5 도입 체크리스트
- [ ] Kafka 4.x KRaft 환경이라면
pinot-kafka-4.0모듈로 교체하고 기존pinot-kafka-2.0/3.0의존을 확인한다. - [ ] Federation 라우팅이 필요하다면 Logical Table 설계를 먼저 완료하고
MultiClusterHelixBrokerStarter를 설정한다. - [ ] MSE를 활성화한 테이블에서 UNNEST 쿼리를 테스트하고 실행계획(EXPLAIN)을 확인한다.
- [ ] Upsert를 쓰는 테이블이라면 commit-time compaction 설정을 검토하고 세그먼트 크기 변화를 모니터링한다.
- [ ] 쿼리 리소스 격리를 쓴다면 쿼리 타입별 메모리 한도를 설정하고 서버 메모리 사용 패턴을 관찰한다.
- [ ] 실시간-오프라인 하이브리드 테이블(Upsert 활성)에서 오프라인 Upsert 지원을 시험하기 전에 테이블 설정 호환성을 확인한다.
- [ ] 새 인덱스(N-gram, IFST)를 도입할 때는 세그먼트 크기 증가와 빌드 시간을 예측하고 운영 디스크 용량을 여유있게 잡는다.
한 문장으로
Pinot 1.5는 멀티클러스터 페더레이션으로 독립 운영과 통합 조회를 양립시키고, MSE 성숙으로 복잡 SQL의 실용 범위를 넓히며, Upsert와 Kafka 4 KRaft 지원으로 운영 의존성을 하나씩 정리한 릴리스다.
References
- Apache Pinot 1.5.0 Release Notes: https://docs.pinot.apache.org/basics/releases/1.5.0
- Releases · apache/pinot (GitHub): https://github.com/apache/pinot/releases
- Logical Table documentation — Apache Pinot Docs: https://docs.pinot.apache.org/architecture-and-concepts/components/table/logical-table
- Apache Pinot Architecture — Apache Pinot Docs: https://docs.pinot.apache.org/architecture-and-concepts/concepts/architecture
- Apache Pinot in 2026 (StarTree): https://startree.ai/resources/apache-pinot-in-2026/
- Apache Pinot Real-Time OLAP 2026 overview: https://pdpspectra.com/blog/apache-pinot-realtime-olap-2026/
- [Federation] multi-cluster routing SSE commit (Apache mail archive): http://www.mail-archive.com/[email protected]/msg117593.html
- [Federation] multi-cluster routing MSE commit (Apache mail archive): http://www.mail-archive.com/[email protected]/msg117732.html