개요
ClickHouse는 Apache Arrow Flight 프로토콜을 지원합니다. 이 프로토콜은 gRPC를 통해 Arrow IPC 포맷을 사용해 열 지향 데이터를 효율적으로 전송할 수 있는 고성능 RPC 프레임워크입니다. 이 구현에는 Arrow Flight SQL 지원도 포함되어 있어, Flight SQL 프로토콜을 사용하는 BI 도구와 애플리케이션이 ClickHouse를 직접 쿼리할 수 있습니다. 주요 기능:- SQL 쿼리를 실행하고 결과를 Apache Arrow 형식으로 가져옵니다.
- Arrow 형식을 사용해 테이블에 데이터를 삽입합니다.
- Flight SQL 명령을 통해 메타데이터(카탈로그, 스키마, 테이블, 프라이머리 키)를 쿼리합니다.
- Flight SQL을 통해 서버 측 prepared statement를 생성, 바인드, 실행, 종료합니다.
- Flight SQL 작업을 통해 세션 및 설정을 관리합니다.
- TLS 암호화와 사용자 이름/비밀번호 인증을 지원합니다.
PollFlightInfo를 통한 점진적 결과 조회.CancelFlightInfo를 통한 쿼리 취소.
Arrow Flight 서버 활성화
Arrow Flight 서버를 활성화하려면 ClickHouse 서버 구성에arrowflight_port 설정을 추가합니다:
TLS 구성
Arrow Flight 인터페이스에서 TLS를 활성화하려면 다음 설정을 지정하십시오:grpc:// 대신 grpc+tls:// 스킴으로 연결해야 합니다.
인증
Arrow Flight 인터페이스는 두 가지 인증 메서드를 지원합니다:기본 인증
클라이언트는 표준 HTTPAuthorization: Basic 헤더를 사용해 사용자 이름과 비밀번호로 인증합니다. 인증에 성공하면 server는 응답 헤더에 Bearer 토큰을 반환합니다.
Bearer 토큰 인증
이후 요청에서는 기본 인증으로 반환된 Bearer 토큰을Authorization: Bearer <token> 헤더를 통해 사용할 수 있습니다. 이 토큰은 사용할 때마다 자동으로 갱신되며, default_session_timeout 서버 설정에 따라 만료됩니다(기본값: 60초).
Python 예시
세션 관리
Arrow Flight 인터페이스는 사용자 지정 gRPC 메타데이터 헤더를 통해 ClickHouse 세션을 지원합니다.Arrow Flight는 HTTP/2 기반 gRPC를 사용하므로 메타데이터 헤더 이름은 대소문자를 구분하며, 아래에 표시된 그대로 반드시 소문자로 지정해야 합니다(예:
x-clickhouse-session-id, X-ClickHouse-Session-Id 아님). 이는 HTTP/2 필드 이름에 소문자만 포함되어야 한다고 규정한 RFC 9113, Section 8.2의 요구 사항입니다. 이는 헤더 이름이 대소문자를 구분하지 않는 HTTP/1.1과 다릅니다.SetSessionOptions action을 통해 ClickHouse 설정을 지속적으로 적용할 수 있습니다(DoAction 참조).
서버 구성 참고
지원되는 RPC 메서드
GetFlightInfo
쿼리를 실행하고 결과 스키마, 데이터 검색에 사용할 티켓이 포함된 엔드포인트, 행 수, 바이트 수를 담은FlightInfo를 반환합니다.
다음 중 하나일 수 있는 FlightDescriptor를 받습니다:
- PATH 디스크립터: table 이름으로 해석되는 단일 구성 요소 경로입니다.
SELECT * FROM <table>를 생성합니다. - CMD 디스크립터: 원시 SQL 쿼리 문자열 또는 직렬화된 Flight SQL protobuf 명령입니다(Flight SQL Commands 참조).
PollFlightInfo
장시간 실행되는 쿼리의 결과를 점진적으로 가져올 수 있도록 합니다. 전체 쿼리가 완료될 때까지 기다리는GetFlightInfo와 달리, PollFlightInfo는 결과를 블록 단위로 반환합니다.
첫 번째 호출 시 쿼리 실행이 시작됩니다. 응답에는 다음이 포함됩니다:
- 현재까지 사용 가능한 데이터 블록의 endpoint가 포함된
FlightInfo - 다음 폴링에 사용할
FlightDescriptor(추가 결과가 예상되는 경우)
현재 구현은 데이터 블록을 사용할 수 있을 때까지 대기하며, 데이터 없이 즉시 반환하지는 않습니다.
GetSchema
전체 쿼리를 실행하지 않고 쿼리 결과의 Arrow 스키마를 반환합니다.GetFlightInfo와 동일한 디스크립터 유형을 지원합니다.
DoGet
지정된 티켓에 대한 데이터를 가져옵니다. 다음 중 하나를 받습니다:GetFlightInfo또는PollFlightInfo에서 반환된 티켓- 티켓 값으로 전달되는 원시 SQL 쿼리 문자열
DoPut
데이터를 ClickHouse로 전송합니다.FlightDescriptor와 Arrow 레코드 배치 스트림을 인수로 받습니다.
테이블 이름으로 삽입 (PATH 디스크립터):
CommandStatementUpdate를 통한 DDL/DML 실행:
Flight SQL 클라이언트는 DDL/DML SQL 문(CREATE, INSERT, ALTER 등)을 실행할 때 CommandStatementUpdate를 사용합니다. 응답에는 영향을 받은 행 수가 포함됩니다.
Flight SQL CommandStatementIngest를 통한 대량 수집:
기존 테이블에 데이터를 추가하는 작업만 지원됩니다(TABLE_NOT_EXIST_OPTION_FAIL + TABLE_EXISTS_OPTION_APPEND). 이 명령에서는 카탈로그와 임시 테이블을 지원하지 않습니다.
transaction_id는 CommandStatementUpdate와 CommandStatementIngest 모두에서 지원되지 않습니다. 이를 제공하면 ClickHouse는 NotImplemented 오류를 반환합니다.
데이터 전송에는
Arrow 형식만 허용됩니다. SQL에서 다른 포맷을 지정하면(예: FORMAT JSON) 오류가 발생합니다.DoAction
명명된 actions를 실행합니다. 지원되는 actions는 다음과 같습니다:CancelFlightInfo
FlightInfo와 연결된 실행 중인 쿼리를 취소합니다. 쿼리 ID는 FlightInfo의 app_metadata 필드에서 추출됩니다. 또한 해당 쿼리와 연결된 모든 폴링 디스크립터도 취소합니다.
SetSessionOptions
현재 세션의 ClickHouse 서버 설정을 지정합니다.x-clickhouse-session-id 헤더를 통해 세션 ID가 설정되어 있어야 합니다.
지원되는 값 타입: string, boolean, integer, double, string list입니다.
설정 이름을 인식할 수 없으면 오류 INVALID_NAME이 반환됩니다. 값을 파싱할 수 없으면 오류 INVALID_VALUE가 반환됩니다.
GetSessionOptions
현재 세션의 모든 ClickHouse 설정과 해당 값을 반환합니다. 설정 이름을 문자열 값에 매핑한 맵을 반환합니다(내부적으로system.settings를 쿼리합니다).
CreatePreparedStatement
서버 측 prepared statement를 생성하고 statement handle을 반환합니다. 요청에는? 플레이스홀더가 포함된 SQL 쿼리 텍스트가 들어 있습니다.
이 작업에서는 transaction_id를 지원하지 않습니다. 이를 제공하면 ClickHouse는 NotImplemented 오류를 반환합니다.
쿼리 SQL 문의 경우 응답에 다음이 포함될 수 있습니다:
dataset_schema: result set의 스키마parameter_schema: SQL 문 매개변수의 스키마
NULL로 대체하는 것이 해당 쿼리에서 유효하지 않은 경우) ClickHouse는 여전히 prepared statement를 생성하고 dataset_schema 없이 handle을 반환합니다.
dataset_schema는 Flight SQL 명세가 의도한 대로 최선의 추측값일 뿐입니다. 명세는 결과 스키마가 매개변수에 따라 달라질 수 있으므로 서버는 최선의 추측을 제공해야 하며, clients는 해당 스키마가 정확하다고 가정해서는 안 된다고 명시합니다. 이 값에 의존하지 마시고, 데이터를 실제로 설명하는 스키마를 얻으려면 SQL 문을 실행하십시오. ClickHouse에서는 다음 두 가지 이유로 실제 제공되는 스키마와 다를 수 있습니다:
- 추론 시 각
?를NULL로 대체하므로, 결과 컬럼을 결정하는 플레이스홀더는 이후에 바인딩하는 값이 아니라 그NULL을 기준으로 타입이 결정됩니다.SELECT ? AS x는Nothing타입의 컬럼으로 추론되지만,5를 바인딩하면UInt8이 제공됩니다.SELECT id, name FROM t WHERE id = ?처럼 프레디케이트에만 사용되는 플레이스홀더는 결과 타입이 테이블에서 결정되므로 이런 문제가 없습니다. - Arrow에 대응하는 타입이 없는 컬럼은
output_format_arrow_unsupported_types에 따라 Arrow 타입이 정해지며, 이 값은 호출을 수행하는 세션마다 각각 해석됩니다. handle은 단일 세션이 아니라 사용자에게 속하므로, 이후 호출에서 다르게 해석되어utf8로 알려졌던 곳에binary가 제공되거나 그 반대의 경우가 발생할 수 있습니다. prepared 쿼리 자체 안에서 모드를 설정하면 두 경우 모두 고정됩니다.
arrowflight.prepared_statements_lifetime_seconds는 만료 동작을 제어합니다:
> 0: 구성된 값을 statement의 수명으로 사용합니다. 세션에 바인딩된 statement와 세션에 바인딩되지 않은 statement 모두에서 각 요청 시 만료 시간이 갱신됩니다.0: prepared statements는 자동으로 만료되지 않습니다.-1(기본값): statement가 세션에서 생성되면 수명은 해당 세션 타임아웃을 따르며, 그 세션의 각 요청 시 갱신됩니다. statement가 세션 없이 생성되면 자동으로 만료되지 않습니다.
arrowflight.max_prepared_statements_per_user에 포함되지 않습니다.
ClosePreparedStatement
요청에 비어 있지 않은 statement handle이 포함된 경우 prepared statement를 닫고, 관련 서버 측 리소스를 해제합니다. ClickHouse는 handle이 비어 있을 때ClosePreparedStatement를 사용한 일괄 종료도 지원합니다.
x-clickhouse-session-id가 있으면 해당 세션에서 인증된 사용자의 모든 prepared statement를 닫습니다.- 세션 ID가 없으면 인증된 사용자의 세션 없는 prepared statement만 닫습니다.
x-clickhouse-session-id를 통해)에서 생성된 경우, 해당 세션이 종료될 때 자동으로 함께 닫힙니다.
Flight SQL 명령
CMD 디스크립터에 직렬화된 Flight SQL protobuf 메시지가 포함된 경우, ClickHouse는 다음 명령을 처리합니다:
GetFlightInfo / GetSchema에서 지원
DoPut을 통해 지원됩니다
ClickHouse에서 지원되지 않음
다음 명령은 ClickHouse에서 제공하지 않는 기능에 해당하므로 Arrow Flight SQL 인터페이스에서 지원되지 않습니다.전체 예시
Query
Response
데이터 포맷
모든 데이터는 Apache Arrow IPC 포맷으로 전송됩니다.Arrow 형식만 지원되며, 다른 ClickHouse 포맷(예: FORMAT JSON, FORMAT CSV)을 지정하면 오류가 발생합니다.
ClickHouse 데이터 타입은 직렬화 과정에서 Arrow 타입으로 매핑됩니다. Arrow Flight는 항상 정규 Arrow 매핑을 사용하며, Arrow 및 ArrowStream 출력 형식과 달리 타입 표현 방식을 바꾸는 output_format_arrow_* 설정을 따르지 않습니다. 즉, output_format_arrow_string_as_string, output_format_arrow_low_cardinality_as_dictionary, output_format_arrow_date_as_uint16, output_format_arrow_fixed_string_as_fixed_byte_array 및 딕셔너리 인덱스 관련 설정은 여기서 아무런 영향을 주지 않습니다. 따라서 동일한 쿼리라도 Arrow Flight에서는 FORMAT Arrow와 다른 스키마가 생성될 수 있으며, 이는 다음 두 가지 이유에서 의도된 설계입니다.
- Flight SQL은 메타데이터 응답의 스키마를 고정합니다. 예를 들어
CommandGetTables는 반드시catalog_name: utf8, db_schema_name: utf8, table_name: utf8 not null, table_type: utf8 not null, table_schema: bytes not null을 반환해야 합니다. 세션 설정으로 이러한utf8컬럼을binary로 바꿀 수 있게 하면 모든 Flight SQL 드라이버에 대해 ClickHouse가 규격을 준수하지 못하게 되고,table_schema안에서 ClickHouse가 알리는 테이블별 스키마까지 달라집니다. - Flight 클라이언트는 스키마와 데이터를 별도의 호출로 가져옵니다(
GetFlightInfo또는GetSchema, 이어서DoGet). 스키마를 바꿀 수 있는 설정이 있다면, 그 사이에 세션이 변경될 경우 알려진 스키마와 실제 전달되는 스트림이 서로 어긋날 수 있습니다.
JSON, Dynamic, QBit, AggregateFunction처럼 Arrow에 대응되는 타입이 아예 없는 경우입니다. 기준으로 삼을 정규 매핑이 없으므로 ClickHouse가 표현 방식을 선택해야 하며, output_format_arrow_unsupported_types로 이를 지정할 수 있습니다.
AggregateFunction 컬럼은 text 모드에서도 Arrow Binary 컬럼으로 남는 유일한 타입입니다. 이 타입의 텍스트 형식은 원시 aggregate state인데, 이는 유효한 UTF-8이 아니며 Arrow Utf8 컬럼에는 유효한 UTF-8만 담을 수 있기 때문입니다. 읽을 수 있는 값이 필요하다면 finalizeAggregation을 사용하십시오.
같은 이유로 ClickHouse는 text 값에 포함된 모든 잘못된 UTF-8 시퀀스를 Utf8 컬럼에 기록하기 전에 U+FFFD(�)로 대체합니다. String을 담고 있는 Dynamic은 해당 바이트를 그대로 직렬화하고 그 값은 임의의 바이트일 수 있으므로, 이러한 처리가 없다면 컬럼이 Arrow 규격을 위반하여 엄격한 클라이언트에서 거부될 수 있습니다. 이미 유효한 텍스트가 아닌 값만 변경됩니다. 바이트를 정확히 보존해야 한다면 binary 모드를 사용하십시오.
output_format_arrow_string_as_string은 FORMAT Arrow에서도 이러한 컬럼에는 적용되지 않으며, 실제 String 및 FixedString 컬럼에만 작용합니다. 따라서 clickhouse.opaque 컬럼의 Arrow 타입은 항상 어떤 인코딩을 담고 있는지를 나타냅니다. 텍스트 형식이면 Utf8, 바이너리 형태면 Binary입니다.
이 때문에 AggregateFunction 컬럼과 달리 Dynamic에 담긴 aggregate state는 text 모드에서 손실이 발생합니다. 해당 컬럼의 타입은 Dynamic으로 정해지는데, 이 타입은 각 행이 무엇을 담고 있는지 전혀 알려주지 않으며, 스키마는 어떤 값을 확인하기도 전에 고정되므로 그 state에 별도의 Binary 컬럼을 부여할 수 없습니다. 값을 그대로 유지하려면 binary 모드를 사용하십시오. 반면 Variant는 가능한 타입들을 모두 나열하므로, 그중에 포함된 AggregateFunction은 자신만의 Binary 자식 컬럼을 갖게 되어 영향을 받지 않습니다.
이러한 컬럼은 그 외에는 실제 Utf8/Binary 컬럼과 구별할 수 없으므로 Arrow 확장 타입으로 선언됩니다. 필드 메타데이터에는 ARROW:extension:name = clickhouse.opaque가 담기고, 원래의 ClickHouse 타입 이름은 ARROW:extension:metadata에 담깁니다. 확장 이름을 인식하지 못하는 클라이언트는 Arrow 규격에 정의된 대로 plain storage 타입을 보게 됩니다. 중첩 컬럼은 각자의 필드에 태그가 지정되므로, 컨테이너 자체가 아니라 Array(JSON)의 자식이 태그를 갖고, Map(JSON, ...)의 키도 마찬가지로 태그를 갖습니다.
기존의 불리언 설정 output_format_arrow_unsupported_types_as_binary도 여전히 동작하며, 0이면 throw, 1이면 binary와 동일합니다. 이 설정은 output_format_arrow_unsupported_types가 기본값으로 유지된 경우에만 참조됩니다.
호환성
Arrow Flight 인터페이스는 Arrow Flight 또는 Arrow Flight SQL 프로토콜을 지원하는 모든 클라이언트나 도구와 호환됩니다. 예를 들면 다음과 같습니다.- Python (
pyarrow) - Java (
org.apache.arrow.flight) - C++ (
arrow::flight) - Go (
apache/arrow/go) - ADBC (Arrow Database Connectivity) 드라이버
- DBeaver 및 Flight SQL을 지원하는 기타 도구