Docker에서 S3와 Pinot 사용하기

Docker에서 S3와 Pinot 사용하기

Docker에서 Pinot을 설정할 때 S3를 딥 스토어로 사용하는 방법을 알려드려요.

출처: 문서

본문

Pinot 클러스터 설정

Docker에서 Pinot을 S3를 딥 스토어로 사용하도록 설정하려면 Controller와 Server에 추가 config를 넣어야 해요.

Docker 네트워크 만들기

docker network create -d bridge pinot-demo

Zookeeper 시작

docker run \
    --name zookeeper \
    --restart always \
    --network=pinot-demo \
    -d zookeeper:3.9.5

Pinot 구성 파일 준비

아래 섹션들은 컨테이너에 마운트할 /tmp/pinot-s3-docker 아래 3개의 config 파일을 준비해요.

/tmp/pinot-s3-docker/
                     controller.conf
                     server.conf
                     ingestionJobSpec.yaml

Controller 시작

아래는 샘플 controller.conf 파일이에요.

controller.data.dir을 s3 버킷으로 구성하세요. 업로드된 모든 세그먼트가 거기에 저장돼요.

그리고 s3를 pinot 저장소로 추가하세요:

pinot.controller.storage.factory.class.s3=org.apache.pinot.plugin.filesystem.S3PinotFS
pinot.controller.storage.factory.s3.region=us-west-2

AWS 자격증명에 관해서는 DefaultAWSCredentialsProviderChain의 관례를 따르세요.

AccessKey와 Secret은 다음을 사용해 지정할 수 있어요:

  • 환경 변수 - AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY(.NET을 제외한 모든 AWS SDK와 CLI가 인식하므로 권장), 또는 AWS_ACCESS_KEY와 AWS_SECRET_KEY(Java SDK만 인식)
  • Java 시스템 속성 - aws.accessKeyId와 aws.secretKey
  • 모든 AWS SDK와 AWS CLI가 공유하는 기본 위치(~/.aws/credentials)의 자격증명 프로필 파일
  • pinot config 파일에 AWS 자격증명 구성(예: config 파일에 pinot.controller.storage.factory.s3.accessKey와 pinot.controller.storage.factory.s3.secretKey 설정) (권장하지 않음)
pinot.controller.storage.factory.s3.accessKey=****************LFVX
pinot.controller.storage.factory.s3.secretKey=****************gfhz

pinot.controller.segment.fetcher.protocols에 s3를 추가하고 pinot.controller.segment.fetcher.s3.class를 org.apache.pinot.common.utils.fetcher.PinotFSSegmentFetcher로 설정하세요.

pinot.role=controller
pinot.controller.storage.factory.class.s3=org.apache.pinot.plugin.filesystem.S3PinotFS
pinot.controller.storage.factory.s3.region=us-west-2
controller.data.dir=s3://<my-bucket>/pinot-data/pinot-s3-example-docker/controller-data/
controller.local.temp.dir=/tmp/pinot-tmp-data/
controller.helix.cluster.name=pinot-s3-example-docker
controller.zk.str=zookeeper:2181
controller.port=9000
controller.enable.split.commit=true
pinot.controller.segment.fetcher.protocols=file,http,s3
pinot.controller.segment.fetcher.s3.class=org.apache.pinot.common.utils.fetcher.PinotFSSegmentFetcher

그런 다음 다음으로 pinot controller를 시작하세요:

docker run --rm -ti \
    --name pinot-controller \
    --network=pinot-demo \
    -p 9000:9000 \
    --env AWS_ACCESS_KEY_ID=<aws-access-key-id> \
    --env AWS_SECRET_ACCESS_KEY=<aws-secret-access-key> \
    --mount type=bind,source=/tmp/pinot-s3-docker,target=/tmp \
    apachepinot/pinot:1.5.1 StartController \
    -configFileName /tmp/controller.conf

Broker 시작

Broker는 간단하므로 기본값으로 시작하면 돼요:

docker run --rm -ti \
    --name pinot-broker \
    --network=pinot-demo \
    --env AWS_ACCESS_KEY_ID=<aws-access-key-id> \
    --env AWS_SECRET_ACCESS_KEY=<aws-secret-access-key> \
    apachepinot/pinot:1.5.1 StartBroker \
    -zkAddress zookeeper:2181 -clusterName pinot-s3-example-docker

Server 시작

아래는 샘플 server.conf 파일이에요.

controller config와 유사하게 pinot server에도 s3 config를 설정하세요.

pinot.server.netty.port=8098
pinot.server.adminapi.port=8097
pinot.server.instance.dataDir=/tmp/pinot-tmp/server/index
pinot.server.instance.segmentTarDir=/tmp/pinot-tmp/server/segmentTars


pinot.server.storage.factory.class.s3=org.apache.pinot.plugin.filesystem.S3PinotFS
pinot.server.storage.factory.s3.region=us-west-2
pinot.server.segment.fetcher.protocols=file,http,s3
pinot.server.segment.fetcher.s3.class=org.apache.pinot.common.utils.fetcher.PinotFSSegmentFetcher

그런 다음 다음으로 pinot server를 시작하세요:

docker run --rm -ti \
    --name pinot-server \
    --network=pinot-demo \
    --env AWS_ACCESS_KEY_ID=<aws-access-key-id> \
    --env AWS_SECRET_ACCESS_KEY=<aws-secret-access-key> \
    --mount type=bind,source=/tmp/pinot-s3-docker,target=/tmp \
    apachepinot/pinot:1.5.1 StartServer \
    -zkAddress zookeeper:2181 -clusterName pinot-s3-example-docker \
    -configFileName /tmp/server.conf

테이블 설정

이 데모에서는 docker 이미지 안에 이미 패키징된 airlineStats 테이블을 예시로 사용해요.

테이블 conf와 schema 파일을 컨테이너에 마운트해 실행할 수도 있어요.

docker run --rm -ti \
    --name pinot-ingestion-job \
    --network=pinot-demo \
    apachepinot/pinot:1.5.1 AddTable \
    -controllerHost pinot-controller \
    -controllerPort 9000 \
    -schemaFile examples/batch/airlineStats/airlineStats_schema.json \
    -tableConfigFile examples/batch/airlineStats/airlineStats_offline_table_config.json \
    -exec

수집 작업 설정 (Ingestion Jobs)

Standalone 작업

특정 변경 사항이 있는 샘플 standalone 수집 job spec은 다음과 같아요:

샘플 ingestionJobSpec.yaml:

# executionFrameworkSpec: 실행할 수집 작업 정의
executionFrameworkSpec:

  # name: 실행 프레임워크 이름
  name: 'standalone'

  # segmentGenerationJobRunnerClassName: org.apache.pinot.spi.batch.ingestion.runner.SegmentGenerationJobRunner 인터페이스를 구현하는 클래스 이름
  segmentGenerationJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentGenerationJobRunner'

  # segmentTarPushJobRunnerClassName: org.apache.pinot.spi.batch.ingestion.runner.SegmentTarPushJobRunner 인터페이스를 구현하는 클래스 이름
  segmentTarPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentTarPushJobRunner'

  # segmentUriPushJobRunnerClassName: org.apache.pinot.spi.batch.ingestion.runner.SegmentUriPushJobRunner 인터페이스를 구현하는 클래스 이름
  segmentUriPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentUriPushJobRunner'

  # segmentMetadataPushJobRunnerClassName: org.apache.pinot.spi.batch.ingestion.runner.IngestionJobRunner 인터페이스를 구현하는 클래스 이름
  segmentMetadataPushJobRunnerClassName: 'org.apache.pinot.plugin.ingestion.batch.standalone.SegmentMetadataPushJobRunner'

# jobType: Pinot 수집 작업 유형
# 지원되는 job 유형:
#   'SegmentCreation'
#   'SegmentTarPush'
#   'SegmentUriPush'
#   'SegmentCreationAndTarPush'
#   'SegmentCreationAndUriPush'
jobType: SegmentCreationAndMetadataPush

# inputDirURI: 입력 데이터의 루트 디렉터리, PinotFS에 구성된 scheme 있어야 함
inputDirURI: 's3://<my-bucket>/pinot-data/rawdata/airlineStats/rawdata/'

# includeFileNamePattern: 포함할 파일 이름 패턴, 전역 glob 패턴 지원
# 샘플 사용법:
#   'glob:*.avro'는 inputDirURI 바로 아래의 avro 파일만 포함, 하위 디렉터리는 제외
#   'glob:**/*.avro'는 inputDirURI 아래의 모든 avro 파일을 재귀적으로 포함
includeFileNamePattern: 'glob:**/*.avro'

# excludeFileNamePattern: 제외할 파일 이름 패턴, 전역 glob 패턴 지원
# 샘플 사용법:
#   'glob:*.avro'는 inputDirURI 바로 아래의 avro 파일만 제외, 하위 디렉터리는 제외
#   'glob:**/*.avro'는 inputDirURI 아래의 모든 avro 파일을 재귀적으로 제외
# _excludeFileNamePattern: ''

# outputDirURI: 출력 세그먼트의 루트 디렉터리, PinotFS에 구성된 scheme 있어야 함
outputDirURI: 's3://<my-bucket>/pinot-data/pinot-s3-docker/segments/airlineStats'

# segmentCreationJobParallelism: 세그먼트 생성 병렬도
segmentCreationJobParallelism: 5

# overwriteOutput: 기존 출력 세그먼트 덮어쓰기 여부
overwriteOutput: true

# pinotFSSpecs: 모든 관련 Pinot 파일 시스템 정의
pinotFSSpecs:

  - # scheme: PinotFS 식별에 사용
    # 예: local, hdfs, dbfs 등
    scheme: file

    # className: PinotFS 인스턴스 생성에 사용되는 클래스 이름
    # 예:
    #   org.apache.pinot.spi.filesystem.LocalPinotFS는 로컬 파일시스템용
    #   org.apache.pinot.plugin.filesystem.AzurePinotFS는 Azure Data Lake용
    #   org.apache.pinot.plugin.filesystem.HadoopPinotFS는 HDFS용
    className: org.apache.pinot.spi.filesystem.LocalPinotFS


  - scheme: s3
    className: org.apache.pinot.plugin.filesystem.S3PinotFS
    configs:
      region: 'us-west-2'

# recordReaderSpec: 모든 record reader 정의
recordReaderSpec:

  # dataFormat: 레코드 데이터 형식, 예: 'avro', 'parquet', 'orc', 'csv', 'json', 'thrift'
  dataFormat: 'avro'

  # className: 해당 RecordReader 클래스 이름
  # 예:
  #   org.apache.pinot.plugin.inputformat.avro.AvroRecordReader
  #   org.apache.pinot.plugin.inputformat.csv.CSVRecordReader
  #   org.apache.pinot.plugin.inputformat.parquet.ParquetRecordReader
  #   org.apache.pinot.plugin.inputformat.json.JSONRecordReader
  #   org.apache.pinot.plugin.inputformat.orc.ORCRecordReader
  #   org.apache.pinot.plugin.inputformat.thrift.ThriftRecordReader
  className: 'org.apache.pinot.plugin.inputformat.avro.AvroRecordReader'

# tableSpec: 테이블 이름과 해당 테이블 config 및 schema를 가져올 위치 정의
tableSpec:

  # tableName: 테이블 이름
  tableName: 'airlineStats'

  # schemaURI: 테이블 스키마를 읽을 위치 정의, PinotFS 또는 HTTP 지원
  # 예:
  #   hdfs://path/to/table_schema.json
  #   http://localhost:9000/tables/myTable/schema
  schemaURI: 'http://pinot-controller:9000/tables/airlineStats/schema'

  # tableConfigURI: 테이블 config를 읽을 위치 정의
  # PinotFS 또는 HTTP 지원
  # 예:
  #   hdfs://path/to/table_config.json
  #   http://localhost:9000/tables/myTable
  # 참고: pinot controller에서 Pinot 테이블 config를 직접 읽는 API는 JSON wrapper를 포함
  # 실제 테이블 config는 'OFFLINE' 필드 아래의 객체
  tableConfigURI: 'http://pinot-controller:9000/tables/airlineStats'

# pinotClusterSpecs: Pinot 클러스터 접근 지점 정의
pinotClusterSpecs:
  - # controllerURI: 테이블/스키마 정보와 데이터 push에 사용
    # 예: http://localhost:9000
    controllerURI: 'http://pinot-controller:9000'

# pushJobSpec: 세그먼트 push 작업 관련 구성 정의
pushJobSpec:

  # pushAttempts: push 작업 시도 횟수, 기본값 1(재시도 없음)
  pushAttempts: 2

  # pushRetryIntervalMillis: 재시도 대기 ms, 기본값 1초
  pushRetryIntervalMillis: 1000

데이터 수집 작업을 실행하세요:

docker run --rm -ti \
    --name pinot-ingestion-job \
    --network=pinot-demo \
    --env AWS_ACCESS_KEY_ID=<aws-access-key-id> \
    --env AWS_SECRET_ACCESS_KEY=<aws-secret-access-key> \
    --mount type=bind,source=/tmp/pinot-s3-docker,target=/tmp \
    apachepinot/pinot:1.5.1 LaunchDataIngestionJob \
    -jobSpecFile /tmp/ingestionJobSpec.yaml

더 알아보기 (Learn more)