ClickHouse клиент на Rust
Официальный клиент Rust для подключения к ClickHouse, первоначально разработанный Paul Loyd. Исходный код клиента доступен в репозитории GitHub.
Обзор
- Использует
serde
для кодирования/декодирования строк. - Поддерживает атрибуты
serde
:skip_serializing
,skip_deserializing
,rename
. - Использует
RowBinary
формат по HTTP транспорту.- Планируется переход на
Native
по TCP.
- Планируется переход на
- Поддерживает TLS (через
native-tls
иrustls-tls
функции). - Поддерживает сжатие и декомпрессию (LZ4).
- Предоставляет API для выборки или вставки данных, выполнения DDL, и клиентской пакетной обработки.
- Предоставляет удобные моки для юнит-тестирования.
Установка
Чтобы использовать пакет, добавьте следующее в ваш Cargo.toml
:
Смотрите также: страница crates.io.
Особенности Cargo
lz4
(включено по умолчанию) — включает вариантыCompression::Lz4
иCompression::Lz4Hc(_)
. Если включено,Compression::Lz4
используется по умолчанию для всех запросов, кромеWATCH
.native-tls
— поддерживает URL с схемойHTTPS
черезhyper-tls
, который ссылается на OpenSSL.rustls-tls
— поддерживает URL с схемойHTTPS
черезhyper-rustls
, который не ссылается на OpenSSL.inserter
— включаетclient.inserter()
.test-util
— добавляет моки. Смотрите пример. Используйте это только вdev-dependencies
.watch
— включает функциональностьclient.watch
. Смотрите соответствующий раздел для деталей.uuid
— добавляетserde::uuid
для работы с uuid пакетом.time
— добавляетserde::time
для работы с time пакетом.
При подключении к ClickHouse по HTTPS
URL либо функция native-tls
, либо rustls-tls
должна быть активирована.
Если обе функции включены, приоритет будет у функции rustls-tls
.
Совместимость версий ClickHouse
Клиент совместим с LTS версиями или новее ClickHouse, а также с ClickHouse Cloud.
Сервер ClickHouse версии ниже v22.6 обрабатывает RowBinary некорректно в некоторых редких случаях.
Вы можете использовать v0.11+ и включить функцию wa-37420
, чтобы решить эту проблему. Примечание: эту функцию не следует использовать с новыми версиями ClickHouse.
Примеры
Мы стремимся охватить различные сценарии использования клиента в примерях в репозитории клиента. Обзор доступен в README примеров.
Если что-то неясно или отсутствует в примерах или в следующей документации, не стесняйтесь связаться с нами.
Использование
Пакет ch2rs полезен для генерации типа строки из ClickHouse.
Создание экземпляра клиента
Повторно используйте созданные клиенты или клонируйте их, чтобы повторно использовать пул соединений hyper.
Подключение через HTTPS или ClickHouse Cloud
HTTPS работает либо с функцией rustls-tls
, либо с native-tls
.
Затем создайте клиента, как обычно. В этом примере используются переменные окружения для хранения деталей подключения:
URL должен включать как протокол, так и порт, например, https://instance.clickhouse.cloud:8443
.
Смотрите также:
- Пример HTTPS с ClickHouse Cloud в репозитории клиента. Это также должно применяться к локальным HTTPS соединениям.
Выбор строк
- Заполнитель
?fields
заменяется наno, name
(поляRow
). - Заполнитель
?
заменяется на значения в следующих вызовахbind()
. - Удобные методы
fetch_one::<Row>()
иfetch_all::<Row>()
могут использоваться для получения первой строки или всех строк соответственно. sql::Identifier
может использоваться для привязки имен таблиц.
Обратите внимание: поскольку весь ответ потоковый, курсоры могут вернуть ошибку даже после генерации некоторых строк. Если это происходит в вашем случае, вы можете попробовать query(...).with_option("wait_end_of_query", "1")
, чтобы включить буферизацию ответа на стороне сервера. Больше деталей. Опция buffer_size
также может быть полезной.
Используйте wait_end_of_query
с осторожностью при выборе строк, так как это может привести к повышенному потреблению памяти на стороне сервера и, вероятно, снизит общую производительность.
Вставка строк
- Если
end()
не вызывается,INSERT
прерывается. - Строки отправляются постепенно как поток, чтобы распределить сетевую нагрузку.
- ClickHouse вставляет пакеты атомарно только если все строки помещаются в ту же партицию и их количество меньше
max_insert_block_size
.
Асинхронная вставка (пакетная обработка на стороне сервера)
Вы можете использовать асинхронные вставки ClickHouse, чтобы избежать пакетной обработки входящих данных на стороне клиента. Это можно сделать, просто передав опцию async_insert
в метод insert
(или даже в экземпляр Client
, чтобы это влияло на все вызовы insert
).
Смотрите также:
- Пример асинхронной вставки в репозитории клиента.
Функция inserter (пакетная обработка на стороне клиента)
Требуется функция inserter
в Cargo.
Inserter
завершает активную вставку вcommit()
, если некоторые из пределов (max_bytes
,max_rows
,period
) достигаются.- Интервал между завершениями активных
INSERT
может быть скорректирован с помощьюwith_period_bias
, чтобы избежать всплесков нагрузки параллельными вставщиками. Inserter::time_left()
может использоваться для определения, когда заканчивается текущий период. Повторно вызывайтеInserter::commit()
, чтобы проверить лимиты, если ваша последовательность редко генерирует элементы.- Пороговые значения времени реализованы с помощью пакета quanta для ускорения работы
inserter
. Не используются, если включенtest-util
(таким образом, время может управляться с помощьюtokio::time::advance()
в пользовательских тестах). - Все строки между вызовами
commit()
вставляются в одномINSERT
выражении.
Не забудьте выполнить сброс, если хотите завершить/закончить вставку:
Выполнение DDL
Для одноузлового развертывания достаточно выполнять DDL следующим образом:
Однако, в кластерных развертываниях с балансировщиком нагрузки или ClickHouse Cloud рекомендуется дождаться применения DDL на всех репликах, используя опцию wait_end_of_query
. Это можно сделать следующим образом:
Настройки ClickHouse
Вы можете применять различные настройки ClickHouse, используя метод with_option
. Например:
Кроме query
, он работает аналогично с методами insert
и inserter
; кроме того, тот же метод может быть вызван на экземпляре Client
, чтобы задать общие настройки для всех запросов.
ID запроса
Используя .with_option
, вы можете задать опцию query_id
, чтобы идентифицировать запросы в журнале запросов ClickHouse.
Кроме query
, он работает аналогично с методами insert
и inserter
.
Если вы задаете query_id
вручную, убедитесь, что он уникален. UUID являются хорошим выбором для этого.
Смотрите также: пример query_id в репозитории клиента.
ID сессии
Аналогично query_id
, вы можете установить session_id
, чтобы выполнять операторы в одной сессии. session_id
может быть установлен либо глобально на уровне клиента, либо для вызова query
, insert
или inserter
.
При кластерных развертываниях, из-за отсутствия "липких сессий", вам нужно быть подключенным к определенному узлу кластера, чтобы правильно использовать эту функцию, так как, например, балансировщик нагрузки типа round-robin не гарантирует, что последующие запросы будут обработаны тем же узлом ClickHouse.
Смотрите также: пример session_id в репозитории клиента.
Пользовательские HTTP заголовки
Если вы используете аутентификацию прокси или необходимо передать пользовательские заголовки, вы можете сделать это следующим образом:
Смотрите также: пример пользовательских HTTP заголовков в репозитории клиента.
Пользовательский HTTP клиент
Это может быть полезно для настройки параметров пула соединений HTTP.
Этот пример основывается на устаревшем API Hyper и может измениться в будущем.
Смотрите также: пример пользовательского HTTP клиента в репозитории клиента.
Типы данных
Смотрите также дополнительные примеры:
(U)Int(8|16|32|64|128)
преобразуется из/в соответствующие(u|i)(8|16|32|64|128)
типы или новые типы вокруг них.(U)Int256
не поддерживаются напрямую, но существует обходное решение.Float(32|64)
преобразуется из/в соответствующиеf(32|64)
или новые типы вокруг них.Decimal(32|64|128)
преобразуется из/в соответствующиеi(32|64|128)
или новые типы вокруг них. Удобнее использоватьfixnum
или другую реализацию знаковых фиксированных чисел.Boolean
преобразуется из/вbool
или новые типы вокруг него.String
преобразуется из/в любые строковые или байтовые типы, например,&str
,&[u8]
,String
,Vec<u8>
илиSmartString
. Поддерживаются также новые типы. Для хранения байтов рассмотрите использованиеserde_bytes
, так как это более эффективно.
FixedString(N)
поддерживается как массив байтов, например,[u8; N]
.
Enum(8|16)
поддерживаются с использованиемserde_repr
.
UUID
преобразуется из/вuuid::Uuid
с использованиемserde::uuid
. Требуется функцияuuid
.
IPv6
преобразуется из/вstd::net::Ipv6Addr
.IPv4
преобразуется из/вstd::net::Ipv4Addr
с использованиемserde::ipv4
.
Date
преобразуется из/вu16
или новый тип вокруг него и представляет собой количество дней, прошедших с1970-01-01
. Также поддерживаетсяtime::Date
с использованиемserde::time::date
, что требует функцииtime
.
Date32
преобразуется из/вi32
или новый тип вокруг него и представляет собой количество дней, прошедших с1970-01-01
. Также поддерживаетсяtime::Date
с использованиемserde::time::date32
, что требует функцииtime
.
DateTime
преобразуется из/вu32
или новый тип вокруг него и представляет собой количество секунд, прошедших с эпохи UNIX. Также поддерживаетсяtime::OffsetDateTime
с использованиемserde::time::datetime
, что требует функцииtime
.
DateTime64(_)
преобразуется из/вi32
или новый тип вокруг него и представляет собой время, прошедшее с эпохи UNIX. Также поддерживаетсяtime::OffsetDateTime
с использованиемserde::time::datetime64::*
, что требует функцииtime
.
Tuple(A, B, ...)
преобразуется из/в(A, B, ...)
или новый тип вокруг него.Array(_)
преобразуется из/в любой срез, например,Vec<_>
,&[_]
. Поддерживаются также новые типы.Map(K, V)
ведет себя какArray((K, V))
.LowCardinality(_)
поддерживается без проблем.Nullable(_)
преобразуется из/вOption<_>
. Для помощниковclickhouse::serde::*
добавьте::option
.
Nested
поддерживается путем предоставления нескольких массивов с переименованием.
- Типы
Geo
поддерживаются.Point
ведет себя как кортеж(f64, f64)
, а остальные типы представляют собой просто срезы точек.
- Типы данных
Variant
,Dynamic
, (новый)JSON
еще не поддерживаются.
Мокирование
Пакет предоставляет утилиты для мокирования сервера CH и тестирования DDL, SELECT
, INSERT
и WATCH
запросов. Функциональность может быть включена с помощью функции test-util
. Используйте это только как зависимость для разработки.
Смотрите пример.
Устранение неполадок
CANNOT_READ_ALL_DATA
Наиболее частой причиной ошибки CANNOT_READ_ALL_DATA
является то, что определение строки на стороне приложения не совпадает с тем, что в ClickHouse.
Рассмотрим следующую таблицу:
Затем, если EventLog
определен на стороне приложения с несовпадающими типами, например:
При вставке данных может возникнуть следующая ошибка:
В этом примере это исправляется правильным определением структуры EventLog
:
Известные ограничения
- Типы данных
Variant
,Dynamic
, (новый)JSON
еще не поддерживаются. - Привязка параметров на стороне сервера еще не поддерживается; смотрите эту проблему для отслеживания.
Связаться с нами
Если у вас есть вопросы или нужна помощь, не стесняйтесь обращаться к нам в Community Slack или через GitHub issues.