고급 Pinot 설정

고급 Pinot 설정 (Advanced Pinot Setup)

Pinot 컴포넌트 시작하기 (스크립트 또는 docker 이미지)

각 컴포넌트를 개별적으로 시작해 Pinot을 설정해요.

출처: 문서

본문

docker 이미지 사용

docker로 Pinot 컴포넌트 시작하기

사전 요구사항

참고: 로컬에서 실행한다면 docker 클러스터에 충분한 리소스가 있는지 확인하세요. 아래는 예시 구성이에요.

Sample Docker resources

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

더 알아보기 (Learn more)