Перейти к основному содержимому
Перейти к основному содержимому

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 — поддерживает 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 через 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.

См. также:

Выбор строк

  • Плейсхолдер ?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, чтобы задать глобальные настройки для всех запросов.

Идентификатор запроса

С помощью .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.
  • 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. Используйте ее только в качестве dev-зависимости.

См. пример.

Устранение неполадок

CANNOT_READ_ALL_DATA

Наиболее распространенной причиной ошибки CANNOT_READ_ALL_DATA является то, что определение строки на стороне приложения не совпадает с тем, что в ClickHouse.

Рассмотрим следующую таблицу:

Тогда, если EventLog определен на стороне приложения с несовпадающими типами, например:

При вставке данных может возникнуть следующая ошибка:

В этом примере это исправляется правильным определением структуры EventLog:

Известные ограничения

  • Variant, Dynamic, (новые) JSON типы данных пока не поддерживаются.
  • Привязка параметров на стороне сервера пока не поддерживается; см. эту проблему для отслеживания.

Свяжитесь с нами

Если у вас есть вопросы или вам нужна помощь, не стесняйтесь обращаться к нам в Community Slack или через GitHub issues.