跳到主要内容
跳到主要内容

ClickHouse Rust 客户端

官方 Rust 客户端,用于连接 ClickHouse,最初由 Paul Loyd 开发。客户端源代码可在 GitHub 仓库 中找到。

概述

  • 使用 serde 进行行的编码/解码。
  • 支持 serde 属性:skip_serializingskip_deserializingrename
  • 通过 HTTP 传输使用 RowBinary 格式。
    • 计划在 TCP 上切换到 Native
  • 支持 TLS(通过 native-tlsrustls-tls 特性)。
  • 支持压缩和解压缩(LZ4)。
  • 提供用于选择或插入数据、执行 DDL 和客户端批处理的 API。
  • 提供方便的单元测试模拟。

安装

要使用该 crate,请将以下内容添加到 Cargo.toml 中:

另请参见:crates.io 页面

Cargo 特性

  • lz4(默认启用)— 启用 Compression::Lz4Compression::Lz4Hc(_) 变体。如果启用,则默认情况下所有查询都将使用 Compression::Lz4,除非是 WATCH
  • native-tls — 通过 hyper-tls 支持带有 HTTPS 架构的 URL,该架构链接到 OpenSSL。
  • rustls-tls — 通过 hyper-rustls 支持带有 HTTPS 架构的 URL,该架构不链接到 OpenSSL。
  • inserter — 启用 client.inserter()
  • test-util — 添加模拟。请参见 示例。仅在 dev-dependencies 中使用。
  • watch — 启用 client.watch 功能。详情请参见相应部分。
  • uuid — 添加 serde::uuid 用于处理 uuid crate。
  • time — 添加 serde::time 用于处理 time crate。
信息

通过 HTTPS URL 连接到 ClickHouse 时,应启用 native-tlsrustls-tls 特性。 如果同时启用了两个特性,则 rustls-tls 特性将优先。

ClickHouse 版本兼容性

该客户端与 LTS 或更高版本的 ClickHouse 以及 ClickHouse Cloud 兼容。

较早于 v22.6 的 ClickHouse 服务器在某些罕见情况下处理 RowBinary 不正确。 您可以使用 v0.11+ 并启用 wa-37420 特性来解决此问题。注意:此特性不应与更新的 ClickHouse 版本一起使用。

示例

我们旨在通过客户端代码库中的 示例 来覆盖客户端使用的各种场景。概述可在 examples README 中找到。

如果示例或以下文档中有不清楚或缺失的信息,请随时 联系我们

使用

备注

ch2rs crate 对于从 ClickHouse 生成行类型非常有用。

创建客户端实例

提示

重用创建的客户端或克隆它们以重用底层的 hyper 连接池。

HTTPS 或 ClickHouse Cloud 连接

HTTPS 可与 rustls-tlsnative-tls cargo 特性一起使用。

然后,像往常一样创建客户端。在这个示例中,使用环境变量来存储连接详细信息:

信息

URL 应包括协议和端口,例如 https://instance.clickhouse.cloud:8443

另请参见:

选择行

  • 占位符 ?fields 被替换为 no, nameRow 的字段)。
  • 占位符 ? 被后续的 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 在达到任何阈值(max_bytesmax_rowsperiod)时会在 commit() 中结束活动插入。
  • 结束活动 INSERT 之间的间隔可以通过使用 with_period_bias 来偏置,以避免通过并行 inserters 引起的负载峰值。
  • Inserter::time_left() 可用于检测当前周期何时结束。如果您的流偶尔发出项,请再次调用 Inserter::commit() 以检查限制。
  • 通过使用 quanta crate 实现的时间阈值加速 inserter。如果启用了 test-util,则不使用(因此,可以通过 tokio::time::advance() 在自定义测试中管理时间)。
  • commit() 调用之间的所有行都插入在同一 INSERT 语句中。
危险

如果您想终止/结束插入,请不要忘记刷新:

执行 DDL

在单节点部署中,执行 DDL 如下:

但是,在具有负载均衡器或 ClickHouse Cloud 的集群部署中,建议等待 DDL 在所有副本上应用,使用 wait_end_of_query 选项。这可以这样完成:

ClickHouse 设置

您可以使用 with_option 方法应用各种 ClickHouse 设置。例如:

除了 query,它在 insertinserter 方法中也类似工作;此外,还可以在 Client 实例上调用相同的方法,以设置所有查询的全局设置。

查询 ID

使用 .with_option,您可以设置 query_id 选项以在 ClickHouse 查询日志中识别查询。

除了 query,它在 insertinserter 方法中也类似工作。

危险

如果您手动设置 query_id,请确保它是唯一的。UUID 是一个不错的选择。

另请参见:query_id 示例 在客户端库中。

会话 ID

query_id 类似,您可以设置 session_id 以在同一会话中执行语句。session_id 可以在客户端级别全局设置,也可以在每个 queryinsertinserter 调用中设置。

危险

对于集群部署,由于缺乏“粘性会话”,您需要连接到 特定的集群节点 以正确利用此特性,因为例如,轮询负载均衡器不会保证后续请求由同一 ClickHouse 节点处理。

另请参见:session_id 示例 在客户端库中。

自定义 HTTP 头

如果您使用代理身份验证或需要传递自定义头,可以这样做:

另请参见:自定义 HTTP 头示例 在客户端库中。

自定义 HTTP 客户端

这对于调整底层 HTTP 连接池的设置可能很有用。

危险

此示例依赖于遗留的 Hyper API,未来可能会发生变化。

另请参见:自定义 HTTP 客户端示例 在客户端库中。

数据类型

  • (U)Int(8|16|32|64|128) 映射到相应的 (u|i)(8|16|32|64|128) 类型或其周围的新类型。
  • (U)Int256 目前不直接支持,但有 一个 workaround
  • Float(32|64) 映射到相应的 f(32|64) 或其周围的新类型。
  • Decimal(32|64|128) 映射到相应的 i(32|64|128) 或其周围的新类型。使用 fixnum 或其他签名定点数实现会更方便。
  • Boolean 映射到 bool 或其周围的新类型。
  • String 映射到任何字符串或字节类型,例如 &str&[u8]StringVec<u8>SmartString。新类型也受支持。要存储字节,可以考虑使用 serde_bytes,因为它更高效。
  • FixedString(N) 作为字节数组支持,例如 [u8; N]
  • 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),其他类型只是点的切片。
  • VariantDynamic、(新) JSON 数据类型尚未得到支持。

模拟

该 crate 提供了模拟 CH 服务器和测试 DDL、SELECTINSERTWATCH 查询的工具。可以通过启用 test-util 特性来启用此功能。仅作为开发依赖使用。

请参见 示例

故障排除

CANNOT_READ_ALL_DATA

CANNOT_READ_ALL_DATA 错误最常见的原因是应用程序端的行定义与 ClickHouse 中不匹配。

考虑以下表:

然后,如果在应用程序端的 EventLog 定义中的类型不匹配,例如:

插入数据时可能会发生以下错误:

在这种情况下,通过正确的 EventLog 结构定义修复:

已知限制

  • VariantDynamic、 (新) JSON 数据类型尚未得到支持。
  • 服务器端参数绑定尚不支持;请参见 这个问题 进行跟踪。

联系我们

如果您有任何问题或需要帮助,请随时通过 Community SlackGitHub issues 与我们联系。