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

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.

Смотрите также:

Выбор строк

  • Плейсхолдер ?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.
  • 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.