고급 Pinot 설정
고급 Pinot 설정 (Advanced Pinot Setup)
Pinot 컴포넌트 시작하기 (스크립트 또는 docker 이미지)
각 컴포넌트를 개별적으로 시작해 Pinot을 설정해요.
출처: 문서
본문
docker 이미지 사용
docker로 Pinot 컴포넌트 시작하기
사전 요구사항
참고: 로컬에서 실행한다면 docker 클러스터에 충분한 리소스가 있는지 확인하세요. 아래는 예시 구성이에요.

Docker 이미지 받기 (Pull)
미리 빌드된 Pinot 올인원(all-in-one) Docker 이미지를 시도해볼 수 있어요.
export PINOT_VERSION=1.4.0 #설치한 Pinot 버전으로 설정
export PINOT_IMAGE=apachepinot/pinot:${PINOT_VERSION}
docker pull ${PINOT_IMAGE}
(선택) 여기의 지침에 따라 직접 이미지를 빌드할 수도 있어요.
0. 네트워크 생성
Docker에 격리된 브리지(bridge) 네트워크를 생성해요.
docker network create -d bridge pinot-demo
1. Zookeeper 시작
Zookeeper를 데몬으로 시작해요.
docker run \
--network=pinot-demo \
--name pinot-zookeeper \
--restart always \
-p 2181:2181 \
-d zookeeper:3.9.5
ZKUI를 시작해 http://localhost:9090에서 Zookeeper 데이터를 탐색해요.
docker run \
--network pinot-demo --name=zkui \
-p 9090:9090 \
-e ZK_SERVER=pinot-zookeeper:2181 \
-d qnib/plain-zkui:latest
2. Pinot Controller 시작
Pinot Controller를 데몬으로 시작하고 Zookeeper에 연결해요.
docker run \
--network=pinot-demo \
--name pinot-controller \
-p 9000:9000 \
-d ${PINOT_IMAGE} StartController \
-zkAddress pinot-zookeeper:2181
3. Pinot Broker 시작
Pinot Broker를 데몬으로 시작하고 Zookeeper에 연결해요.
docker run \
--network=pinot-demo \
--name pinot-broker \
-d ${PINOT_IMAGE} StartBroker \
-zkAddress pinot-zookeeper:2181
4. Pinot Server 시작
Pinot Server를 데몬으로 시작하고 Zookeeper에 연결해요.
export PINOT_IMAGE=apachepinot/pinot:latest
docker run \
--network=pinot-demo \
--name pinot-server \
-d ${PINOT_IMAGE} StartServer \
-zkAddress pinot-zookeeper:2181
이제 모든 Pinot 관련 컴포넌트가 빈 클러스터로 시작됐어요.
아래 명령으로 컨테이너 상태를 확인할 수 있어요.
docker container ls -a
콘솔 출력 예시
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9e80c3fcd29b apachepinot/pinot:latest "./bin/pinot-admin.s…" 18 seconds ago Up 17 seconds 8096-8099/tcp, 9000/tcp pinot-server
f4c42a5865c7 apachepinot/pinot:latest "./bin/pinot-admin.s…" 21 seconds ago Up 21 seconds 8096-8099/tcp, 9000/tcp pinot-broker
a413b0013806 apachepinot/pinot:latest "./bin/pinot-admin.s…" 26 seconds ago Up 25 seconds 8096-8099/tcp, 0.0.0.0:9000->9000/tcp pinot-controller
9d3b9c4d454b zookeeper:3.9.5 "/docker-entrypoint.…" About a minute ago Up About a minute 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, 8080/tcp pinot-zookeeper
런처 스크립트 사용 (Using launcher scripts)
http://pinot.apache.org/download/에서 Pinot Distribution을 다운로드해요.
$ export PINOT_VERSION=1.4.0 #설치한 Pinot 버전으로 설정
$ tar -xvf apache-pinot-${PINOT_VERSION}-bin.tar.gz
$ cd apache-pinot-${PINOT_VERSION}-bin
$ ls
DISCLAIMER LICENSE NOTICE bin conf lib licenses query_console sample_data
$ PINOT_INSTALL_DIR=`pwd`
런처 스크립트로 Pinot 컴포넌트 시작하기
Zookeeper 시작
cd apache-pinot-${PINOT_VERSION}-bin
bin/pinot-admin.sh StartZookeeper
Pinot Controller 시작
자세한 내용은 controller page를 참고하세요.
bin/pinot-admin.sh StartController \
-zkAddress localhost:2181
Pinot Broker 시작
bin/pinot-admin.sh StartBroker \
-zkAddress localhost:2181
Pinot Server 시작
bin/pinot-admin.sh StartServer \
-zkAddress localhost:2181
구성 파일로 Pinot 시작 (Start Pinot Using Config Files)
종종 Pinot 컴포넌트 설정을 사용자화해야 하는 경우가 있어요. 사용자는 구성 파일을 작성해 Pinot 컴포넌트를 시작할 수 있어요.
아래는 Pinot을 시작하는 예시 구성 파일과 샘플 명령이에요.
Pinot Controller
HelmChart 설정에 쓰이는 샘플 pinot-controller.conf예요.
controller.helix.cluster.name=pinot-quickstart
controller.port=9000
controller.vip.host=pinot-controller
controller.vip.port=9000
controller.data.dir=/var/pinot/controller/data
controller.zk.str=pinot-zookeeper:2181
pinot.set.instance.id.to.hostname=true
Pinot Controller를 실행하려면 명령은 다음과 같아요:
bin/pinot-admin.sh StartController -configFileName config/pinot-controller.conf
Controller 구성하기
Pinot Controller에서 설정할 수 있는 구성 일부예요. 사용 가능한 전체 구성 목록은 Controller에서 확인할 수 있어요.
| 구성 이름 | 설명 | 기본값 |
|---|---|---|
| controller.helix.cluster.name | Pinot 클러스터 이름 | PinotCluster |
| controller.host | Pinot Controller 호스트 | 구성 pinot.set.instance.id.to.hostname이 false면 필수. |
| pinot.set.instance.id.to.hostname | 활성화 시 서버 호스트 이름으로 controller.host 추론 | false |
| controller.port | Pinot Controller 포트 | 9000 |
| controller.vip.host | 세그먼트 다운로드 URL 설정에 쓰는 VIP 호스트 이름 | ${controller.host} |
| controller.vip.port | 세그먼트 다운로드 URL 설정에 쓰는 VIP 포트 | ${controller.port} |
| controller.data.dir | 세그먼트 데이터를 호스팅할 디렉토리 | ${java.io.tmpdir}/PinotController |
| controller.zk.str | Zookeeper URL | localhost:2181 |
| cluster.tenant.isolation.enable | 테넌트 격리 활성화. 기본값은 단일 테넌트 클러스터 | true |
Pinot Broker
HelmChart 설정에 쓰이는 샘플 pinot-broker.conf예요.
pinot.broker.client.queryPort=8099
pinot.broker.routing.table.builder.class=random
pinot.set.instance.id.to.hostname=true
Pinot Broker를 실행하려면 명령은 다음과 같아요:
bin/pinot-admin.sh StartBroker -clusterName pinot-quickstart -zkAddress pinot-zookeeper:2181 -configFileName config/pinot-broker.conf
Broker 구성하기
Pinot Broker에서 설정할 수 있는 구성 일부예요. 사용 가능한 전체 구성 목록은 Broker에서 확인할 수 있어요.
| 구성 이름 | 설명 | 기본값 |
|---|---|---|
| instanceId | 클러스터에 Pinot Broker를 등록할 고유 id. | BROKER_${BROKER_HOST}_${pinot.broker.client.queryPort} |
| pinot.set.instance.id.to.hostname | 활성화 시 위 구성의 ${BROKER_HOST}에 서버 호스트 이름을 사용하고, 아니면 IP 주소를 사용해요. | false |
| pinot.broker.client.queryPort | Pinot Broker에 쿼리할 포트 | 8099 |
| pinot.broker.timeoutMs | Broker 쿼리 타임아웃(밀리초) | 10000 |
| pinot.broker.enable.query.limit.override | 너무 많은 레코드를 가져오는 것으로부터 Pinot Broker와 Server를 보호하기 위해 Query LIMIT Override를 활성화하는 구성. | false |
| pinot.broker.query.response.limit | 구성 pinot.broker.enable.query.limit.override가 활성화되면, selection 쿼리의 limit이 이 값을 초과할 때 해당 값으로 리셋해요. | 2147483647 |
| pinot.broker.startup.minResourcePercent | 이 브로커가 서빙해야 하는 전체 테이블 수 중 ONLINE인 리소스(테이블)의 백분율이 이 임계 백분율을 넘으면 브로커 ServiceStatus를 STARTED로 간주하는 구성. | 100.0 |
Pinot Server
HelmChart 설정에 쓰이는 샘플 pinot-server.conf예요.
pinot.server.netty.port=8098
pinot.server.adminapi.port=8097
pinot.server.instance.dataDir=/var/pinot/server/data/index
pinot.server.instance.segmentTarDir=/var/pinot/server/data/segment
pinot.set.instance.id.to.hostname=true
Pinot Server를 실행하려면 명령은 다음과 같아요:
bin/pinot-admin.sh StartServer -clusterName pinot-quickstart -zkAddress pinot-zookeeper:2181 -configFileName config/pinot-server.conf
Server 구성하기
Pinot Server에서 설정할 수 있는 주요 구성 일부예요. 사용 가능한 전체 구성 목록은 Server에서 확인할 수 있어요.
| 구성 이름 | 설명 | 기본값 |
|---|---|---|
| instanceId | 클러스터에 Pinot Server를 등록할 고유 id. | Server_${SERVER_HOST}_${pinot.server.netty.port} |
| pinot.set.instance.id.to.hostname | 활성화 시 위 구성의 ${SERVER_HOST}에 서버 호스트 이름을 사용하고, 아니면 IP 주소를 사용해요. | false |
| pinot.server.netty.port | Pinot Server에 쿼리할 포트 | 8098 |
| pinot.server.adminapi.port | Pinot Server Admin UI 포트 | 8097 |
| pinot.server.instance.dataDir | 모든 데이터를 보관할 디렉토리 | ${java.io.tmpDir}/PinotServer/index |
| pinot.server.instance.segmentTarDir | Controller나 Deep Store에서 다운로드한 임시 세그먼트를 보관할 디렉토리 | ${java.io.tmpDir}/PinotServer/segmentTar |
| pinot.server.query.executor.timeout | Server가 쿼리를 처리하는 타임아웃(밀리초) | 15000 |
테이블 생성 및 구성 (Create and Configure table)
일반 데이터베이스 세계의 TABLE은 적재 모드(배치, 실시간, 하이브리드)에 따라 Pinot에서 <TABLE>_OFFLINE 및/또는 <TABLE>_REALTIME으로 표현돼요.
가능한 모든 배치/스트리밍 테이블은 examples를 참고하세요.
배치 테이블 생성 (Batch Table Creation)
테이블 구성 상세와 사용자화 방법은 Batch Tables를 참고하세요.
Docker
docker run \
--network=pinot-demo \
--name pinot-batch-table-creation \
${PINOT_IMAGE} AddTable \
-schemaFile examples/batch/airlineStats/airlineStats_schema.json \
-tableConfigFile examples/batch/airlineStats/airlineStats_offline_table_config.json \
-controllerHost pinot-controller \
-controllerPort 9000 \
-exec
콘솔 출력 예시
Executing command: AddTable -tableConfigFile examples/batch/airlineStats/airlineStats_offline_table_config.json -schemaFile examples/batch/airlineStats/airlineStats_schema.json -controllerHost pinot-controller -controllerPort 9000 -exec
Sending request: http://pinot-controller:9000/schemas to controller: a413b0013806, version: Unknown
{"status":"Table airlineStats_OFFLINE succesfully added"}
런처 스크립트 사용
bin/pinot-admin.sh AddTable \
-schemaFile examples/batch/airlineStats/airlineStats_schema.json \
-tableConfigFile examples/batch/airlineStats/airlineStats_offline_table_config.json \
-exec
배치 테이블에 역인덱스 자동 추가
기본적으로 역인덱스(inverted index) 타입은 세그먼트 생성 중 자동으로 만들어지지 않는 유일한 인덱스 타입이에요. 대신 세그먼트가 서버에 로드될 때 생성돼요. 하지만 인덱스 빌드를 로드 시간까지 미루면 시작 시간이 늘어나고 새 세그먼트 푸시마다 리소스를 차지해, 리밸런스 같은 다른 작업의 시간이 늘어나요.
세그먼트 생성 중 역인덱스를 자동으로 만들려면 테이블 구성 파일의 table index config에 항목을 추가하세요.
이 설정은 배치(오프라인) 테이블에서 동작해요.
true로 설정하면 Pinot은 테이블 구성의 invertedIndexColumns 목록에 지정한 컬럼에 역인덱스를 생성해요.
이 설정의 기본값은 false예요.
테이블 구성에서 createInvertedIndexDuringSegmentGeneration을 true로 설정하세요:
...
"tableIndexConfig": {
...
"createInvertedIndexDuringSegmentGeneration": true,
...
}
...
테이블 구성에서 이 설정을 갱신하면, 기존 모든 세그먼트에 역인덱스를 적용하려면 테이블 세그먼트를 다시 로드(segment reload)해야 해요.
스트리밍 테이블 생성 (Streaming Table Creation)
테이블 구성 상세와 사용자화 방법은 Streaming Tables를 참고하세요.
Docker
Kafka 시작
docker run \
--network pinot-demo --name=kafka \
-e KAFKA_NODE_ID=1 \
-e KAFKA_PROCESS_ROLES=broker,controller \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \
-e KAFKA_CONTROLLER_QUORUM_VOTERS=1@kafka:9093 \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
-e CLUSTER_ID=MkU3OEVBNTcwNTJENDM2Qk \
-d apache/kafka:4.0.0
Kafka 토픽 생성
docker exec \
-t kafka \
/opt/kafka/bin/kafka-topics.sh \
--bootstrap-server kafka:9092 \
--partitions=1 --replication-factor=1 \
--create --topic flights-realtime
스트리밍 테이블 생성
docker run \
--network=pinot-demo \
--name pinot-streaming-table-creation \
${PINOT_IMAGE} AddTable \
-schemaFile examples/stream/airlineStats/airlineStats_schema.json \
-tableConfigFile examples/docker/table-configs/airlineStats_realtime_table_config.json \
-controllerHost pinot-controller \
-controllerPort 9000 \
-exec
샘플 출력
Executing command: AddTable -tableConfigFile examples/docker/table-configs/airlineStats_realtime_table_config.json -schemaFile examples/stream/airlineStats/airlineStats_schema.json -controllerHost pinot-controller -controllerPort 9000 -exec
Sending request: http://pinot-controller:9000/schemas to controller: 8fbe601012f3, version: Unknown
{"status":"Table airlineStats_REALTIME succesfully added"}
런처 스크립트 사용
참고: Pinot의 내장
StartKafka런처는 coordination에 ZooKeeper를 사용하는 임베디드 Kafka 인스턴스를 시작해요. 이는 Docker 탭에 보이는 독립형 Kafka 4.0(KRaft 모드)과 다르다는 점을 유의하세요.
Kafka-Zookeeper 시작
bin/pinot-admin.sh StartZookeeper -zkPort 2181
Kafka 시작
bin/pinot-admin.sh StartKafka -zkAddress=localhost:2181/kafka -port 19092
스트림 테이블 생성
bin/pinot-admin.sh AddTable \
-schemaFile examples/stream/airlineStats/airlineStats_schema.json \
-tableConfigFile examples/stream/airlineStats/airlineStats_realtime_table_config.json \
-exec
스트리밍 테이블에서 sortedColumn 사용
스트리밍 테이블의 경우 sortedColumn으로 정렬 인덱스를 사용해 세그먼트가 생성될 때 데이터를 정렬할 수 있어요. 자세한 내용은 Real-time tables을 참고하세요.
정렬된 forward index는 더 나은 성능의 역인덱스로 쓸 수 있지만, 검색이 테이블당 한 컬럼에만 적용된다는 제한이 있어요. 자세한 내용은 Sorted inverted index를 참고하세요.
데이터 적재 (Load Data)
이제 테이블이 구성됐으니 데이터를 적재해봐요. 데이터는 배치 모드 또는 스트리밍 모드로 적재할 수 있어요. 자세한 내용은 ingestion overview 페이지를 참고하세요. 데이터 적재는 원시 데이터에서 pinot 세그먼트를 생성하고 이를 pinot 클러스터로 푸시하는 것을 포함해요.
배치로 데이터 적재 (Load Data in Batch)
사용자는 독립 실행형 스크립트나 Hadoop, Spark 같은 프레임워크로 세그먼트를 생성해 Pinot으로 푸시할 수 있어요. Data Ingestion Job 설정에 대한 자세한 내용은 이 페이지를 참고하세요.
아래 예시는 독립 실행형(standalone) 모드예요.
Docker
docker run \
--network=pinot-demo \
--name pinot-data-ingestion-job \
${PINOT_IMAGE} LaunchDataIngestionJob \
-jobSpecFile examples/docker/ingestion-job-specs/airlineStats.yaml
콘솔 출력 예시
SegmentGenerationJobSpec:
!!org.apache.pinot.spi.ingestion.batch.spec.SegmentGenerationJobSpec
excludeFileNamePattern: null
executionFrameworkSpec: {extraConfigs: null, name: standalone, segmentGenerationJobRunnerClassName: org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner,
segmentTarPushJobRunnerClassName: org.apache.pinot.plugin.ingestion.batch.standalone.SegmentTarPushJobRunner,
segmentUriPushJobRunnerClassName: org.apache.pinot.plugin.ingestion.batch.standalone.SegmentUriPushJobRunner}
includeFileNamePattern: glob:**/*.avro
inputDirURI: examples/batch/airlineStats/rawdata
jobType: SegmentCreationAndTarPush
outputDirURI: examples/batch/airlineStats/segments
overwriteOutput: true
pinotClusterSpecs:
- {controllerURI: 'http://pinot-controller:9000'}
pinotFSSpecs:
- {className: org.apache.pinot.spi.filesystem.LocalPinotFS, configs: null, scheme: file}
pushJobSpec: {pushAttempts: 2, pushParallelism: 1, pushRetryIntervalMillis: 1000,
segmentUriPrefix: null, segmentUriSuffix: null}
recordReaderSpec: {className: org.apache.pinot.plugin.inputformat.avro.AvroRecordReader,
configClassName: null, configs: null, dataFormat: avro}
segmentNameGeneratorSpec: null
tableSpec: {schemaURI: 'http://pinot-controller:9000/tables/airlineStats/schema',
tableConfigURI: 'http://pinot-controller:9000/tables/airlineStats', tableName: airlineStats}
Trying to create instance for class org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner
Initializing PinotFS for scheme file, classname org.apache.pinot.spi.filesystem.LocalPinotFS
Finished building StatsCollector!
Collected stats for 403 documents
Created dictionary for INT column: FlightNum with cardinality: 386, range: 14 to 7389
Using fixed bytes value dictionary for column: Origin, size: 294
Created dictionary for STRING column: Origin with cardinality: 98, max length in bytes: 3, range: ABQ to VPS
Created dictionary for INT column: Quarter with cardinality: 1, range: 1 to 1
Created dictionary for INT column: LateAircraftDelay with cardinality: 50, range: -2147483648 to 303
......
......
Pushing segment: airlineStats_OFFLINE_16085_16085_29 to location: http://pinot-controller:9000 for table airlineStats
Sending request: http://pinot-controller:9000/v2/segments?tableName=airlineStats to controller: a413b0013806, version: Unknown
Response for pushing table airlineStats segment airlineStats_OFFLINE_16085_16085_29 to location http://pinot-controller:9000 - 200: {"status":"Successfully uploaded segment: airlineStats_OFFLINE_16085_16085_29 of table: airlineStats"}
Pushing segment: airlineStats_OFFLINE_16084_16084_30 to location: http://pinot-controller:9000 for table airlineStats
Sending request: http://pinot-controller:9000/v2/segments?tableName=airlineStats to controller: a413b0013806, version: Unknown
Response for pushing table airlineStats segment airlineStats_OFFLINE_16084_16084_30 to location http://pinot-controller:9000 - 200: {"status":"Successfully uploaded segment: airlineStats_OFFLINE_16084_16084_30 of table: airlineStats"}
런처 스크립트 사용
bin/pinot-admin.sh LaunchDataIngestionJob \
-jobSpecFile examples/batch/airlineStats/ingestionJobSpec.yaml
JobSpec yaml 파일에는 데이터 형식, 입력 데이터 위치, pinot 클러스터 좌표에 관한 모든 정보가 담겨 있어요. 이는 컨트롤러가 테이블 구성과 스키마를 가져오기 위해 RUNNING(실행 중) 상태임을 가정한다는 점을 유의하세요. 그렇지 않으면 스펙이 해당 위치를 가리키도록 구성해야 해요. 자세한 내용은 Pinot Ingestion Job을 참고하세요.
스트리밍으로 데이터 적재 (Load Data in Streaming)
Kafka
Docker — 아래 명령으로 JSON 데이터를 Kafka 토픽 flights-realtime으로 스트리밍해요:
docker run \
--network pinot-demo \
--name=loading-airlineStats-data-to-kafka \
${PINOT_IMAGE} StreamAvroIntoKafka \
-avroFile examples/stream/airlineStats/sample_data/airlineStats_data.avro \
-kafkaTopic flights-realtime -kafkaBrokerList kafka:9092 -zkAddress pinot-zookeeper:2181/kafka
런처 스크립트 사용 — 아래 명령으로 JSON 데이터를 Kafka 토픽 flights-realtime으로 스트리밍해요:
bin/pinot-admin.sh StreamAvroIntoKafka \
-avroFile examples/stream/airlineStats/sample_data/airlineStats_data.avro \
-kafkaTopic flights-realtime -kafkaBrokerList localhost:19092 -zkAddress localhost:2181/kafka