Обзор
ClickHouse поддерживает протокол Apache Arrow Flight — высокопроизводительный RPC-фреймворк для эффективной передачи столбцовых данных в формате Arrow IPC поверх gRPC. Реализация также поддерживает Arrow Flight SQL, что позволяет BI-инструментам и приложениям, работающим по протоколу Flight SQL, отправлять запросы к ClickHouse напрямую. Основные возможности:- Выполнение SQL-запросов и получение результатов в формате Apache Arrow.
- Вставка данных в таблицы с использованием формата Arrow.
- Запрос метаданных (каталогов, схем, таблиц, первичных ключей) через команды Flight SQL.
- Создание, связывание, выполнение и закрытие серверных подготовленных операторов через Flight SQL.
- Управление сеансами и настройками через действия Flight SQL.
- Шифрование TLS и аутентификация по имени пользователя и паролю.
- Поэтапное получение результатов через
PollFlightInfo. - Отмена запросов через
CancelFlightInfo.
Включение сервера Arrow Flight
Чтобы включить сервер Arrow Flight, добавьте настройкуarrowflight_port в конфигурацию сервера ClickHouse:
Настройка TLS
Чтобы включить TLS для интерфейса Arrow Flight, настройте следующие параметры:grpc+tls:// вместо grpc://.
Аутентификация
Интерфейс Arrow Flight поддерживает два метода аутентификации:Базовая аутентификация
Клиенты проходят аутентификацию по имени пользователя и паролю через стандартный HTTP-заголовокAuthorization: Basic. При успешной аутентификации server возвращает Bearer-токен в заголовке ответа.
Аутентификация с Bearer-токеном
В последующих запросах можно использовать Bearer-токен, полученный при базовой аутентификации, передавая его в заголовкеAuthorization: Bearer <token>. Токен автоматически обновляется при каждом использовании и действует до истечения времени, заданного настройкой сервера default_session_timeout (по умолчанию — 60 секунд).
Пример на Python
Управление сеансами
Интерфейс Arrow Flight поддерживает сеансы ClickHouse с помощью пользовательских заголовков метаданных gRPC:Поскольку Arrow Flight использует gRPC поверх HTTP/2, имена заголовков метаданных учитывают регистр и должны быть указаны строчными буквами точно так, как показано (например,
x-clickhouse-session-id, а не X-ClickHouse-Session-Id). Это требование RFC 9113, раздел 8.2, согласно которому имена полей HTTP/2 должны содержать только строчные символы. В отличие от этого, в HTTP/1.1 имена заголовков регистронезависимы.SetSessionOptions (см. DoAction).
Справочник по конфигурации сервера
Поддерживаемые методы RPC
GetFlightInfo
Выполняет запрос и возвращаетFlightInfo, содержащий схему результата, конечные точки с тикетами для получения данных, число строк и число байтов.
Принимает FlightDescriptor, который может быть одним из следующих:
- дескриптор PATH: Путь с одним компонентом, интерпретируемый как имя таблицы. Генерирует
SELECT * FROM <table>. - дескриптор CMD: Либо исходную строку SQL-запроса, либо сериализованную protobuf-команду Flight SQL (см. Команды Flight SQL).
PollFlightInfo
Позволяет получать результаты длительно выполняющихся запросов по мере готовности. Вместо того чтобы ждать завершения всего запроса (как в случае сGetFlightInfo), PollFlightInfo возвращает результаты блоками.
При первом вызове запрос начинает выполняться. Ответ включает:
FlightInfoс конечными точками для всех блоков данных, доступных на текущий момент.FlightDescriptorдля следующего опроса (если ожидаются дополнительные результаты).
Текущая реализация ждёт, пока не станет доступен блок данных, вместо того чтобы сразу возвращать ответ без данных.
GetSchema
Возвращает схему Arrow для результата запроса без выполнения всего запроса. Поддерживает те же типы дескрипторов, что иGetFlightInfo.
DoGet
Извлекает данные по указанному тикету. Принимает одно из следующего:- Тикет, возвращённый
GetFlightInfoилиPollFlightInfo. - Необработанную строку SQL-запроса в качестве значения тикета.
DoPut
Отправляет данные в ClickHouse. ПринимаетFlightDescriptor и поток батчей записей Arrow.
Вставка по имени таблицы (дескриптор PATH):
CommandStatementUpdate:
Клиенты Flight SQL используют CommandStatementUpdate для выполнения DDL/DML-команд (CREATE, INSERT, ALTER и т. д.). В ответе возвращается количество затронутых строк.
Пакетный приём через Flight SQL CommandStatementIngest:
Поддерживается только добавление данных в существующие таблицы (TABLE_NOT_EXIST_OPTION_FAIL + TABLE_EXISTS_OPTION_APPEND). Каталоги и временные таблицы для этой команды не поддерживаются.
transaction_id не поддерживается для CommandStatementUpdate и CommandStatementIngest. Если он указан, ClickHouse возвращает ошибку NotImplemented.
Для передачи данных поддерживается только формат
Arrow. Указание других форматов в SQL (например, FORMAT JSON) приводит к ошибке.DoAction
Выполняет именованные действия. Поддерживаются следующие из них:CancelFlightInfo
Отменяет выполняемый запрос, связанный сFlightInfo. Идентификатор запроса извлекается из поля app_metadata объекта FlightInfo. Также отменяет все дескрипторы опроса, связанные с этим запросом.
SetSessionOptions
Устанавливает настройки сервера ClickHouse для текущего сеанса. Для этого требуется, чтобы идентификатор сеанса был задан через заголовокx-clickhouse-session-id.
Поддерживаемые типы значений: string, boolean, integer, double и списки строк.
Если имя настройки неизвестно, возвращается ошибка INVALID_NAME. Если значение не удаётся разобрать, возвращается ошибка INVALID_VALUE.
GetSessionOptions
Возвращает все текущие настройки ClickHouse и их значения для данного сеанса. Возвращает сопоставление имён настроек со строковыми значениями (внутри выполняет запрос кsystem.settings).
CreatePreparedStatement
Создаёт подготовленный оператор на стороне сервера и возвращает дескриптор оператора. Запрос содержит текст SQL-запроса с плейсхолдерами?.
transaction_id для этого действия не поддерживается. Если он указан, ClickHouse возвращает ошибку NotImplemented.
Для операторов запроса ответ может включать:
dataset_schema: схема результирующего набора.parameter_schema: схема параметров оператора.
NULL недопустима для этого запроса), ClickHouse всё равно создаёт подготовленный оператор и возвращает дескриптор без dataset_schema.
dataset_schema — это наилучшее предположение, как и предусматривает спецификация Flight SQL: в ней указано, что схема результата может зависеть от параметров, что сервер должен дать наилучшее предположение и что клиенты не должны считать схему точной. Не полагайтесь на неё; выполните оператор, чтобы получить схему, описывающую данные. В ClickHouse она может отличаться от фактически отдаваемой по двум причинам:
- При определении схемы каждый
?заменяется наNULL, поэтому плейсхолдер, определяющий столбец результата, получает тип от этогоNULL, а не от значения, которое вы привяжете позже.SELECT ? AS xопределяет столбец типаNothing, но при привязке5отдаётсяUInt8. У плейсхолдера, используемого только в предикате, как вSELECT id, name FROM t WHERE id = ?, такой проблемы нет, поскольку типы результата берутся из таблицы. - Столбец, не имеющий эквивалента в Arrow, получает свой тип Arrow из
output_format_arrow_unsupported_types, которое каждый вызов разрешает из сеанса, из которого он выполняется. Поскольку дескриптор принадлежит пользователю, а не одному сеансу, последующий вызов может разрешить его иначе и отдатьbinaryтам, где был заявленutf8, или наоборот. Установка режима внутри самого подготовленного запроса фиксирует его для обоих случаев.
arrowflight.prepared_statements_lifetime_seconds управляет поведением при истечении срока действия:
> 0: использовать настроенное значение как время жизни оператора. Срок действия обновляется при каждом запросе как для операторов, привязанных к сеансу, так и для операторов, не привязанных к сеансу.0: подготовленные операторы не истекают автоматически.-1(по умолчанию): если оператор создан в сеансе, его время жизни соответствует тайм-ауту этого сеанса и обновляется при каждом запросе в этом сеансе. Если оператор создан без сеанса, он не истекает автоматически.
arrowflight.max_prepared_statements_per_user.
ClosePreparedStatement
Закрывает подготовленный оператор и освобождает связанные с ним ресурсы на стороне сервера, если запрос содержит непустой дескриптор оператора. ClickHouse также поддерживает массовое закрытие с помощьюClosePreparedStatement, когда дескриптор пуст:
- Если указан
x-clickhouse-session-id, закрываются все подготовленные операторы аутентифицированного пользователя в этом сеансе. - Если идентификатор сеанса не указан, закрываются только подготовленные операторы без сеанса для аутентифицированного пользователя.
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, ClickHouse перестал бы соответствовать спецификации для любого драйвера Flight SQL, а также изменилась бы схема отдельных таблиц, которую ClickHouse объявляет внутриtable_schema. - Клиент Flight получает схему и данные разными вызовами (
GetFlightInfoилиGetSchema, затемDoGet). Любая настройка, способная изменить схему, открывает возможность рассогласования между объявленной схемой и переданным потоком, если в промежутке сеанс изменится.
JSON, Dynamic, QBit или AggregateFunction. Канонического отображения, на которое можно опереться, нет, поэтому ClickHouse должен выбрать представление, а настройка output_format_arrow_unsupported_types позволяет указать, какое именно:
Столбец
AggregateFunction — единственный тип, который остаётся столбцом Arrow Binary даже в режиме text: его текстовая форма — это сырое агрегатное состояние, не являющееся корректным UTF-8, а столбец Arrow Utf8 обязан содержать корректный UTF-8. Если нужно читаемое значение, используйте finalizeAggregation.
По той же причине ClickHouse заменяет каждую некорректную последовательность UTF-8 в значении text на U+FFFD (�), прежде чем записать его в столбец Utf8. Dynamic, содержащий String, сериализует эти байты дословно, а они могут быть произвольными, поэтому без такой замены столбец нарушал бы спецификацию Arrow и мог бы быть отклонён строгим клиентом. Изменяются только значения, которые и так не являются корректным текстом. Если байты должны сохраняться в точности, используйте режим binary.
Настройка output_format_arrow_string_as_string никогда не применяется к таким столбцам, в том числе и в FORMAT Arrow — она управляет только настоящими столбцами String и FixedString. Поэтому тип Arrow у столбца clickhouse.opaque всегда указывает, какое кодирование он содержит: Utf8 для текстовой формы, Binary для двоичной.
Именно поэтому агрегатное состояние, содержащееся в Dynamic, теряет информацию в режиме text, хотя столбец AggregateFunction — нет. Столбец типизируется из Dynamic, который ничего не говорит о содержимом своих строк, а схема фиксируется до того, как будет просмотрено хоть одно значение, поэтому состоянию нельзя выделить собственный столбец Binary. Чтобы сохранить его, используйте режим binary. Variant перечисляет свои альтернативы, поэтому AggregateFunction среди них получает собственный дочерний столбец Binary и остаётся незатронутым.
В остальном такой столбец неотличим от настоящего Utf8/Binary, поэтому он объявляется расширенным типом Arrow: метаданные поля содержат ARROW:extension:name = clickhouse.opaque, а исходное имя типа ClickHouse — в ARROW:extension:metadata. Клиент, не распознающий имя расширения, видит обычный тип хранения, как предписывает спецификация Arrow. Вложенные столбцы помечаются в собственном поле, поэтому метку несёт дочерний элемент 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