CLI로 Pinot 세그먼트 업로드

CLI로 Pinot 세그먼트 업로드 (Upload Pinot Segment Using CLI)

이미 만들어진 Pinot 세그먼트를 컨트롤러에 업로드하는 방법과, 어떤 REST 엔드포인트를 호출할지, tar push·URI push·metadata push를 언제 쓸지 설명하는 페이지예요.

출처: Upload Pinot Segment Using CLI

본문

이 가이드는 이미 빌드된 Pinot 세그먼트를 Pinot 컨트롤러에 업로드하는 방법을 설명해요. 예를 들어 이전 클러스터에서 마이그레이션하거나, 다른 시스템에서 백필하거나, 딥스토어에 이미 있는 세그먼트를 다시 등록할 때처럼 세그먼트 .tar.gz 파일이 Pinot 밖에 이미 존재하는 경우에 이 흐름을 사용해요.

업로드 전에 다음을 수행하세요:

  1. 스키마 설정 생성 또는 업로드할 세그먼트와 일치하는 스키마가 이미 있는지 확인.
  2. 테이블 설정 생성 또는 업로드할 세그먼트와 일치하는 테이블이 이미 있는지 확인.
  3. 필요하다면 스키마와 테이블 설정을 업로드.
pinot-admin.sh AddTable \
  -tableConfigFile /path/to/table-config.json \
  -schemaFile /path/to/table-schema.json -exec
  1. 컨트롤러가 세그먼트 소스를 읽을 수 있는지 확인:
    • tar push의 경우 클라이언트가 세그먼트 tar 파일을 컨트롤러로 스트리밍할 수 있어야 해요.
    • URI push와 metadata push의 경우 컨트롤러가 사용하는 URI 스킴에 접근할 수 있어야 해요. HDFS, S3, GCS, ADLS 같은 PinotFS 기반 스킴은 일치하는 Pinot 파일 시스템을 설정하세요. 커스텀 스킴은 세그먼트 페처 (segment fetcher)를 구현하세요.

컨트롤러 업로드 엔드포인트

컨트롤러는 세 가지 업로드 엔드포인트를 제공해요:

엔드포인트 (Endpoint) 사용 사례 (Use case) 콘텐츠 타입 (Content type) 참고 (Notes)
POST /v2/segments 선호하는 단일 세그먼트 업로드 엔드포인트 multipart/form-data 또는 application/json tar push, URI push, metadata push 모두에 권장
POST /segments 레거시 단일 세그먼트 업로드 엔드포인트 multipart/form-data 또는 application/json 여전히 지원되지만 /v2/segments 권장
POST /segments/batchUpload 배치 metadata push multipart/form-data 여러 세그먼트의 metadata push만 지원

/v2/segments는 기본적으로 문서화·사용할 엔드포인트예요. 레거시 /segments 엔드포인트는 하위 호환성을 위해 여전히 존재해요. 그 JSON 기반 URI push 경로는 세그먼트를 Pinot이 정한 최종 위치로 옮기는 대신 원래의 DOWNLOAD_URI를 유지하므로, 새 통합은 /v2/segments를 사용해야 해요.

멀티파트 업로드를 위한 컨트롤러 디스크 공간

컨트롤러는 멀티파트 요청 본문을 로컬 임시 볼륨에 버퍼링해요. 멀티파트 스필 파일은 이제 java.io.tmpdir이 아니라 컨트롤러 로컬 임시 디렉터리의 multipartTemp 하위 디렉터리에 저장돼요. 그 디렉터리는 controller.local.temp.dir로 설정하세요; 설정하지 않으면 Pinot이 로컬 controller.data.dir에서 파생해요. 특히 JVM 임시 디렉터리와 다른 마운트라면 동시 세그먼트 업로드에 맞춰 로컬 임시 볼륨 크기를 정하세요. 컨트롤러는 시작 시 multipartTemp의 오래된 파일을 정리해요. 이는 multipart/form-data를 쓰는 tar·metadata push 요청에 영향을 주며, 업로드 엔드포인트와 요청 형식은 바뀌지 않아요. Pinot PR #19627 참고.

공통 요청 옵션

쿼리 파라미터

세 가지 업로드 모드 모두 같은 쿼리 파라미터를 사용해요:

쿼리 파라미터 (Query parameter) 필수 (Required) 기본값 (Default) 설명 (Description)
tableName 단일 업로드 권장, 배치 업로드 필수 없음 업로드할 테이블 이름. Pinot이 세그먼트 메타데이터에서 파생할 수 있지만 명시적으로 전달하는 게 좋아요.
tableType 아니오 OFFLINE OFFLINE 또는 REALTIME
enableParallelPushProtection 아니오 false 같은 세그먼트의 동시 업로드를 거부
allowRefresh 아니오 true 기존 세그먼트 업로드 실패 대신 리프레시 허용

예시:

POST /v2/segments?tableName=myTable&tableType=OFFLINE&enableParallelPushProtection=false&allowRefresh=true

헤더

헤더 (Header) 필수 (Required) 적용 대상 (Applies to) 설명 (Description)
UPLOAD_TYPE tar push엔 아니오, URI·metadata push엔 예 모든 업로드 SEGMENT(기본), URI, 또는 METADATA
DOWNLOAD_URI URI push·metadata push엔 예 URI push, metadata push 세그먼트 tar 파일의 소스 URI
COPY_SEGMENT_TO_DEEP_STORE 아니오 metadata push true면 컨트롤러가 세그먼트를 소스 URI에서 Pinot 딥스토어로 복사하고 저장된 다운로드 URI를 다시 씀
CRYPTER 아니오 모든 업로드 업로드된 페이로드가 암호화된 경우의 Crypter 클래스 이름

오프라인 업서트 업로드 검증 (Offline upsert upload validation)

오프라인 업서트 테이블의 경우, Pinot이 테이블 설정에서 파티션 컬럼을 해석할 수 있을 때 추가 업로드 시점 검증을 적용해요. Pinot은 먼저 instanceAssignmentConfigMap.OFFLINE을 확인하고, 그다음 레거시 replicaGroupStrategyConfig.partitionColumn, 마지막으로 단일 컬럼 segmentPartitionConfig를 확인해요.

그 설정 중 하나가 파티션 컬럼을 식별하면, 모든 업로드된 세그먼트는 세그먼트 메타데이터에서 그 컬럼에 대해 정확히 하나의 파티션 ID를 노출해야 해요. 이는 단일 세그먼트 업로드 엔드포인트와 POST /segments/batchUpload 모두에 적용돼요.

예를 들어 Pinot이 playerId를 파티션 컬럼으로 해석하면, 세그먼트 메타데이터는 column.playerId.partitionValues=2 같은 값을 하나 포함해야 해요. 그 컬럼의 파티션 메타데이터가 없거나 2,3 같은 여러 파티션 ID를 나열하면 업로드는 400 BAD_REQUEST로 거부돼요.

푸시 모드 (Push modes)

Tar push

Tar push는 원래의 기본 업로드 모드예요. 클라이언트가 전체 세그먼트 tar 파일을 컨트롤러로 스트리밍할 수 있을 때 사용해요.

요청 형식 (Request shape)

  • 엔드포인트: POST /v2/segments
  • 콘텐츠 타입: multipart/form-data
  • 헤더: UPLOAD_TYPE 생략 또는 SEGMENT로 설정
  • 본문: 세그먼트 .tar.gz를 담은 멀티파트 파일 파트 하나

컨트롤러가 수행하는 일

  1. 업로드된 세그먼트를 컨트롤러의 세그먼트 디렉터리 또는 딥스토어에 저장.
  2. 세그먼트 메타데이터 추출.
  3. 대상 테이블에 세그먼트 추가 또는 리프레시.

예시:

curl -X POST "http://localhost:9000/v2/segments?tableName=myTable&tableType=OFFLINE" \
  -F "file=@/path/to/myTable_2024-01-01_2024-01-02_0.tar.gz"

Pinot CLI를 선호한다면, pinot-admin.sh UploadSegment는 로컬 세그먼트 디렉터리에 대해 tar push를 사용해요:

pinot-admin.sh UploadSegment \
  -controllerHost localhost \
  -controllerPort 9000 \
  -segmentDir /path/to/local/dir \
  -tableName myTable

URI push

URI push는 세그먼트 tar 파일이 딥스토어나 컨트롤러가 읽을 수 있는 다른 원격 시스템에 이미 있을 때 가장 좋아요.

요청 형식

  • 엔드포인트: POST /v2/segments
  • 콘텐츠 타입: application/json
  • 헤더:
    • UPLOAD_TYPE: URI
    • DOWNLOAD_URI: <segment-tar-uri>
  • 본문: 빈 JSON 페이로드로 충분함; 컨트롤러는 헤더를 사용

컨트롤러가 수행하는 일

  1. DOWNLOAD_URI에서 세그먼트 tar를 다운로드.
  2. 컨트롤러의 세그먼트 디렉터리 또는 딥스토어에 저장.
  3. 메타데이터 추출.
  4. 테이블에 세그먼트 추가 또는 리프레시.

예시:

curl -X POST "http://localhost:9000/v2/segments?tableName=myTable&tableType=OFFLINE" \
  -H "Content-Type: application/json" \
  -H "UPLOAD_TYPE: URI" \
  -H "DOWNLOAD_URI: s3://bucket/pinot-segments/myTable_2024-01-01_2024-01-02_0.tar.gz" \
  -d '{}'

URI push는 컨트롤러가 URI 스킴을 해석할 수 있을 때만 사용하세요. 소스가 HDFS, S3, GCS, ADLS 또는 커스텀 시스템이라면 적절한 Pinot 파일 시스템 또는 세그먼트 페처로 Pinot을 설정하세요.

Metadata push

Metadata push는 세그먼트 tar가 접근 가능한 스토리지 시스템에 이미 있을 때 가장 컨트롤러-효율적인 옵션이에요.

전체 세그먼트 tar를 업로드하는 대신, 클라이언트가 세그먼트 메타데이터를 업로드하고 tar가 이미 어디에 있는지 컨트롤러에 알려줘요.

요청 형식

  • 엔드포인트: POST /v2/segments
  • 콘텐츠 타입: multipart/form-data
  • 헤더:
    • UPLOAD_TYPE: METADATA
    • DOWNLOAD_URI: <segment-tar-uri>
    • 선택: COPY_SEGMENT_TO_DEEP_STORE: true
  • 본문: 세그먼트의 메타데이터 tarball을 담은 멀티파트 파일 파트 하나

메타데이터 tarball에는 세그먼트 메타데이터 파일(보통 creation.meta와 metadata.properties)이 들어 있어요.

컨트롤러가 수행하는 일

  1. 업로드된 메타데이터 번들을 읽음.
  2. DOWNLOAD_URI를 세그먼트 다운로드 위치로 사용.
  3. 메타데이터만 검사하기 위해 전체 tar를 다운로드하지 않고 테이블에 세그먼트 추가 또는 리프레시.

COPY_SEGMENT_TO_DEEP_STORE: true를 설정하면 컨트롤러가 DOWNLOAD_URI에서 세그먼트를 Pinot 딥스토어로 복사하고 최종 딥스토어 URI를 세그먼트 메타데이터에 저장해요. 수집 잡이 최종 딥스토어 경로 대신 스테이징 위치에 쓸 때 유용해요.

예시:

curl -X POST "http://localhost:9000/v2/segments?tableName=myTable&tableType=OFFLINE" \
  -H "UPLOAD_TYPE: METADATA" \
  -H "DOWNLOAD_URI: s3://staging-bucket/segments/myTable_2024-01-01_2024-01-02_0.tar.gz" \
  -H "COPY_SEGMENT_TO_DEEP_STORE: true" \
  -F "file=@/path/to/myTable_2024-01-01_2024-01-02_0.metadata.tar.gz"

COPY_SEGMENT_TO_DEEP_STORE는 metadata push에서만 유용해요. 복사가 PinotFS를 통해 일어나므로 스테이징 URI와 Pinot 딥스토어는 같은 스토리지 스킴을 사용해야 해요.

배치 metadata push (Batch metadata push)

한 번의 호출로 많은 세그먼트를 metadata push해야 한다면 POST /segments/batchUpload를 사용해요.

요청 형식

  • 엔드포인트: POST /segments/batchUpload
  • 콘텐츠 타입: multipart/form-data
  • 쿼리 파라미터: tableName과 tableType 필수
  • 헤더: UPLOAD_TYPE: METADATA
  • 본문: 다음을 담은 uber tarball 멀티파트 파트 하나:
    • 각 세그먼트의 creation.meta
    • 각 세그먼트의 metadata.properties
    • 세그먼트 이름을 DOWNLOAD_URI 값으로 매핑하는 all_segments_metadata 파일

이 엔드포인트는 metadata push 전용이에요.

잡 유형과 Pinot Admin 매핑

배치 수집 잡에서 푸시한다면 jobType은 컨트롤러 업로드 모드로 다음과 같이 매핑돼요:

잡 유형 (Job type) 푸시 모드 (Push mode) 컨트롤러 엔드포인트 (Controller endpoint)
SegmentTarPush 또는 SegmentCreationAndTarPush Tar push POST /v2/segments
SegmentUriPush 또는 SegmentCreationAndUriPush URI push POST /v2/segments
SegmentMetadataPush 또는 SegmentCreationAndMetadataPush Metadata push POST /v2/segments
SegmentMetadataPush + batchSegmentUpload: true Batch metadata push POST /segments/batchUpload

수집 잡의 경우 수집 잡 스펙에서 푸시 동작을 정의해요. 예시:

executionFrameworkSpec:
  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
  segmentMetadataPushJobRunnerClassName: org.apache.pinot.plugin.ingestion.batch.standalone.SegmentMetadataPushJobRunner

jobType: SegmentCreationAndMetadataPush

pinotClusterSpecs:
  - controllerURI: http://localhost:9000

pushJobSpec:
  pushAttempts: 2
  pushRetryIntervalMillis: 1000
  copyToDeepStoreForMetadataPush: true

그다음 다음과 같이 실행해요:

pinot-admin.sh LaunchDataIngestionJob \
  -jobSpecFile /path/to/job-spec.yaml

올바른 모드 선택하기

모드 (Mode) 언제 사용하나 (Use it when) 트레이드오프 (Tradeoff)
Tar push 클라이언트가 세그먼트 tar를 로컬에서 보유해 직접 업로드할 수 있을 때 컨트롤러로 보내는 페이로드가 가장 큼
URI push 세그먼트 tar가 컨트롤러가 읽을 수 있는 URI에 이미 존재할 때 컨트롤러가 여전히 전체 세그먼트 tar를 다운로드
Metadata push 세그먼트 tar가 이미 원격에 존재하고 가장 가벼운 컨트롤러-측 등록 경로를 원할 때 메타데이터 번들과 유효한 DOWNLOAD_URI 필요

딥스토어가 설정된 프로덕션 클러스터에서는 SegmentCreationAndMetadataPush가 일반적으로 선호되는 수집 잡 모드예요.

더 알아보기 (Learn more)