구성 검증기 SPI

구성 검증기 SPI (Config Validator SPI)

Pinot가 테이블·인스턴스 구성을 영속화하기 전에 검증하는 방법을 다루는 문서예요. 이를 통해 구성 생성·업데이트 동안 실행되는 커스텀 검증 로직을 구현할 수 있어요.

출처: 문서

본문

Pinot는 테이블·인스턴스 구성을 영속화하기 전에 검증하기 위한 SPI(서비스 제공자 인터페이스)를 제공해요. 이를 통해 구성 생성·업데이트 동안 실행되는 커스텀 검증 로직을 구현할 수 있어요.

두 가지 검증기 인터페이스가 있어요:

  1. TableConfigValidator - 테이블 구성 변경 사항 검증
  2. InstanceConfigValidator - 인스턴스 구성 변경 사항 검증

두 검증기 모두 단락(short-circuit) 의미론과 동일한 등록·호출 패턴을 따라요: 구성을 처음으로 거부하는 검증기가 추가 검증을 중단하고 즉시 예외를 발생시켜요.

TableConfigValidator

인터페이스 정의 (Interface Definition)

package org.apache.pinot.spi.config.table;

public interface TableConfigValidator {
  /**
   * Validates a table configuration.
   *
   * @param tableConfig the table configuration to validate
   * @param schema the table schema (nullable)
   * @throws ConfigValidationException if validation fails
   */
  void validate(TableConfig tableConfig, @Nullable Schema schema) 
      throws ConfigValidationException;
}

등록 (Registration)

다음을 사용해 검증기를 등록해요:

TableConfigValidatorRegistry.register(new MyTableConfigValidator());

호출 (Invocation)

검증기는 테이블 구성이 영속화되기 전에 다음 동안 호출돼요:

  • 테이블 생성
  • 테이블 업데이트
  • POST /tableConfigs/validate를 통한 사전 검증
  • POST /tables/validate를 통한 사전 검증

여러 검증기를 등록할 수 있으며 등록 순서대로 호출돼요. ConfigValidationException을 던지는 첫 검증기가 작업을 거부하고 나머지 검증기를 단락시켜요.

두 사전 검증 엔드포인트 모두 테이블 구성을 영속화하지 않고 등록된 검증기를 실행해요. 해당 create·update 요청을 제출하기 전에 커스텀 검증 실패를 잡으려면 두 엔드포인트 중 하나를 사용해요.

InstanceConfigValidator

인터페이스 정의 (Interface Definition)

package org.apache.pinot.spi.config.instance;

public interface InstanceConfigValidator {
  /**
   * Validates an instance configuration.
   *
   * @param instance the instance configuration to validate
   * @throws ConfigValidationException if validation fails
   */
  void validate(Instance instance) throws ConfigValidationException;
}

등록 (Registration)

다음을 사용해 검증기를 등록해요:

InstanceConfigValidatorRegistry.register(new MyInstanceConfigValidator());

호출 (Invocation)

검증기는 인스턴스 구성이 영속화되기 전에 다음 동안 호출돼요:

  • 인스턴스 추가
  • 인스턴스 업데이트
  • 인스턴스 태그 업데이트

테이블 검증기와 유사하게, 여러 인스턴스 검증기를 동일한 단락 의미론으로 등록할 수 있어요.

ConfigValidationException

검증이 실패하면 ConfigValidationException을 던져요:

package org.apache.pinot.spi.exception;

public class ConfigValidationException extends RuntimeException {
  public ConfigValidationException(String message) {
    super(message);
  }

  public ConfigValidationException(String message, Throwable cause) {
    super(message, cause);
  }
}

이 예외는 REST API 경계에서 HTTP 400(Bad Request)로 매핑되어, 잘못된 구성을 시도하는 클라이언트에게 즉각적인 피드백을 제공해요.

중요한 요구 사항 (Important Requirements)

스레드 안전성 (Thread Safety)

검증기 구현은 스레드 안전해야 해요. 검증기는 여러 스레드에서 동시에 호출될 수 있으므로, 구현이 공유 상태에 대한 동시 접근을 올바르게 처리하는지 확인하세요.

모범 사례 (Best Practices)

  1. 빠른 실패 (Fail Fast) - 일찍 검증하고 명확한 오류 메시지 제공
  2. 무상태 (Stateless) - 가능하면 검증기를 무상태로 유지
  3. 부작용 없음 (No Side Effects) - 검증기는 구성만 검증해야 하며 수정하면 안 됨
  4. 명확한 메시지 (Clear Messages) - 오류 메시지에 실행 가능한 정보 포함

예시: 테이블 이름 접두사 검증기 (Example: Table Name Prefix Validator)

테이블 이름이 특정 명명 규칙을 따르도록 강제하는 검증기 예시예요:

import org.apache.pinot.spi.config.table.TableConfig;
import org.apache.pinot.spi.config.table.TableConfigValidator;
import org.apache.pinot.spi.exception.ConfigValidationException;
import org.apache.pinot.spi.data.Schema;
import javax.annotation.Nullable;

public class TableNamePrefixValidator implements TableConfigValidator {
  private final String requiredPrefix;

  public TableNamePrefixValidator(String requiredPrefix) {
    this.requiredPrefix = requiredPrefix;
  }

  @Override
  public void validate(TableConfig tableConfig, @Nullable Schema schema) 
      throws ConfigValidationException {
    String tableName = tableConfig.getTableName();
    
    if (!tableName.startsWith(requiredPrefix)) {
      throw new ConfigValidationException(
          String.format(
              "Table name '%s' must start with prefix '%s'",
              tableName,
              requiredPrefix
          )
      );
    }
  }
}

이 검증기를 등록하려면:

TableConfigValidatorRegistry.register(
    new TableNamePrefixValidator("prod_")
);

이제 prod_ 접두사가 없는 테이블을 만들거나 업데이트하려는 모든 시도는 명확한 오류 메시지와 함께 거부돼요.

예시: 인스턴스 태그 검증기 (Example: Instance Tag Validator)

인스턴스 구성을 위한 검증기 예시예요:

import org.apache.pinot.spi.config.instance.Instance;
import org.apache.pinot.spi.config.instance.InstanceConfigValidator;
import org.apache.pinot.spi.exception.ConfigValidationException;

public class InstanceTagValidator implements InstanceConfigValidator {
  private static final String REQUIRED_TAG = "monitoring_enabled";

  @Override
  public void validate(Instance instance) throws ConfigValidationException {
    if (!instance.getTags().contains(REQUIRED_TAG)) {
      throw new ConfigValidationException(
          String.format(
              "Instance '%s' must have the '%s' tag",
              instance.getInstanceId(),
              REQUIRED_TAG
          )
      );
    }
  }
}

등록:

InstanceConfigValidatorRegistry.register(new InstanceTagValidator());

통합 지점 (Integration Points)

검증기는 다음 REST 엔드포인트에서 호출돼요:

테이블 구성:

  • POST /tables (테이블 생성)
  • PUT /tables/{tableName} (테이블 업데이트)

인스턴스 구성:

  • POST /instances (인스턴스 추가)
  • PUT /instances/{instanceId} (인스턴스 업데이트)
  • PUT /instances/{instanceId}/tags (태그 업데이트)

검증 실패는 응답 본문에 예외 메시지와 함께 HTTP 400을 반환해요.

더 알아보기 (Learn more)