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

ClickHouse Rust 客户端

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

概述

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

安装

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

另请参见:crates.io 页面

Cargo 特性

  • lz4(默认启用)— 启用 Compression::Lz4Compression::Lz4Hc(_) 变体。如果启用,除 WATCH 外,默认情况下所有查询使用 Compression::Lz4
  • 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 兼容。

旧版本 ClickHouse 服务器(v22.6 之前)在某些罕见情况下错误处理 RowBinary 问题。 您可以使用 v0.11 及以上版本并启用 wa-37420 特性来解决此问题。注意:此特性不应与更新的 ClickHouse 版本一起使用。

示例

我们旨在通过客户端仓库中的 示例 涵盖客户机使用的各种场景。概述可在 示例 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 异步插入 来避免客户端对传入数据的批处理。这可以通过简单地向 insert 方法(甚至直接向 Client 实例)提供 async_insert 选项来完成,这样它会影响所有 insert 调用。

另请参见:

插入器功能(客户端批处理)

需要 inserter cargo 特性。

  • Inserter 如果达到任何阈值(max_bytesmax_rowsperiod),则在 commit() 中结束活动插入。
  • 结束活动 INSERT 的间隔可以通过使用 with_period_bias 据以避免并行插入器造成的负载峰值。
  • 可以使用 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 目前不直接支持,但有 解决方案
  • 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 以来经过的天数。此外,可以使用 serde::time::date 支持 time::Date,这需要 time 特性。
  • Date32 映射到 i32 或围绕它的新类型,表示自 1970-01-01 以来经过的天数。此外,可以使用 serde::time::date32 支持 time::Date,这需要 time 特性。
  • DateTime 映射到 u32 或围绕它的新类型,表示自 UNIX 纪元以来经过的秒数。此外,可以使用 serde::time::datetime 支持 time::OffsetDateTime,这需要 time 特性。
  • DateTime64(_) 映射到 i32 或一个围绕它的新类型,表示自 UNIX 纪元以来经过的时间。此外,可以使用 serde::time::datetime64::* 支持 time::OffsetDateTime,这需要 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 数据类型尚未支持。
  • 服务器端参数绑定尚未支持;有关跟踪的请参见 此问题

联系我们

如果您有任何问题或需要帮助,请随时通过 社区 Slack 或通过 GitHub 问题 与我们联系。