ClickHouse Rust Client
Официальный клиент 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
— поддерживает URLs со схемойHTTPS
черезhyper-tls
, который ссылается на OpenSSL.rustls-tls
— поддерживает URLs со схемойHTTPS
черезhyper-rustls
, который не ссылается на OpenSSL.inserter
— включаетclient.inserter()
.test-util
— добавляет мока. Смотрите пример. Используйте только вdev-dependencies
.watch
— включает функциональностьclient.watch
. Смотрите соответствующий раздел для деталей.uuid
— добавляетserde::uuid
для работы с крейтом uuid.time
— добавляетserde::time
для работы с крейтом 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 примеров.
Если что-то не ясно или отсутствует в примерах или в следующей документации, не стесняйтесь связаться с нами.
Использование
Крейт 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
.
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
.
В кластерных развертываниях, из-за отсутствия "липких сессий", вам нужно быть подключенным к определенной ноде кластера, чтобы правильно использовать эту функцию, поскольку, например, балансировщик нагрузки с округлением не гарантирует, что последующие запросы будут обработаны одной и той же нодой 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.