Клиент 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 и пакетирования на стороне клиента.
- Предоставляет удобные моки для юнит-тестирования.
Установка
Чтобы использовать crate, добавьте следующее в ваш 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
для работы с crate uuid.time
— добавляетserde::time
для работы с crate time.
При подключении к ClickHouse через URL-адрес HTTPS
должна быть включена либо функция native-tls
, либо rustls-tls
. Если обе включены, функция rustls-tls
будет иметь приоритет.
Совместимость версий ClickHouse
Клиент совместим с LTS или более новыми версиями ClickHouse, а также с ClickHouse Cloud.
Сервер ClickHouse старше v22.6 неправильно обрабатывает RowBinary в некоторых редких случаях. Вы можете использовать v0.11+ и включить функцию wa-37420
, чтобы решить эту проблему. Примечание: эта функция не должна использоваться с более новыми версиями ClickHouse.
Примеры
Мы стремимся охватить различные сценарии использования клиента в примерах в репозитории клиента. Обзор доступен в README примеров.
Если что-то непонятно или отсутствует в примерах или в следующей документации, не стесняйтесь связаться с нами.
Использование
crate ch2rs полезен для генерации типа строки из ClickHouse.
Создание экземпляра клиента
Повторно используйте созданные клиенты или копируйте их, чтобы повторно использовать базовый пул соединений hyper.
Подключение по HTTPS или к ClickHouse Cloud
HTTPS работает с любыми из особенностей cargo, 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
).
Смотрите также:
- Пример асинхронной вставки в репозитории клиента.
Функция вставки (пакетирование на стороне клиента)
Требует активации функции cargo inserter
.
Inserter
завершает активную вставку вcommit()
, если один из пределов (max_bytes
,max_rows
,period
) достигнут.- Интервал между завершением активных
INSERT
можно изменять с помощьюwith_period_bias
, чтобы избежать пиковых нагрузок от параллельных вставщиков. Inserter::time_left()
можно использовать для определения, когда текущий период закончится. ВызывайтеInserter::commit()
снова, чтобы проверить лимиты, если ваш поток выводит элементы редко.- Пороговые значения времени реализуются с помощью crate 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
, чтобы задать глобальные настройки для всех запросов.
Идентификатор запроса
Используя .with_option
, вы можете установить опцию query_id
, чтобы идентифицировать запросы в журнале запросов ClickHouse.
Кроме query
, это также работает аналогично с методами insert
и inserter
.
Если вы задаете query_id
вручную, убедитесь, что он уникален. UUID являются хорошим выбором для этого.
Смотрите также: пример query_id в репозитории клиента.
Идентификатор сессии
Аналогично query_id
, вы можете установить session_id
, чтобы выполнять операторы в одной сессии. session_id
может быть установлен либо глобально на уровне клиента, либо для каждого вызова query
, insert
или inserter
.
При развертывании в кластере, из-за отсутствия "липких сессий", вам необходимо подключиться к определенному узлу кластера, чтобы правильно использовать эту функцию, так как, например, балансировщик нагрузки "кругом" не гарантирует, что последующие запросы будут обрабатываться тем же узлом 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
еще не поддерживаются.
Мокирование
crate предоставляет утилиты для мокирования сервера 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.