ClickHouse Rust 客户端
官方 Rust 客户端,用于连接 ClickHouse,最初由 Paul Loyd 开发。客户端源代码可在 GitHub 仓库 中找到。
概述
- 使用
serde
进行行的编码/解码。 - 支持
serde
属性:skip_serializing
,skip_deserializing
,rename
。 - 通过 HTTP 传输使用
RowBinary
格式。- 计划在 TCP 上切换到
Native
。
- 计划在 TCP 上切换到
- 支持 TLS(通过
native-tls
和rustls-tls
特性)。 - 支持压缩和解压缩(LZ4)。
- 提供用于选择或插入数据、执行 DDL 和客户端批处理的 API。
- 提供方便的单元测试模拟。
安装
要使用该 crate,请将以下内容添加到 Cargo.toml
中:
另请参见:crates.io 页面。
Cargo 特性
lz4
(默认启用)— 启用Compression::Lz4
和Compression::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-tls
或 rustls-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-tls
或 native-tls
cargo 特性一起使用。
然后,像往常一样创建客户端。在这个示例中,使用环境变量来存储连接详细信息:
URL 应包括协议和端口,例如 https://instance.clickhouse.cloud:8443
。
另请参见:
- HTTPS with 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
调用)来完成。
另请参见:
- Async insert 示例 在客户端库中。
Inserter 特性(客户端批处理)
需要 inserter
cargo 特性。
Inserter
在达到任何阈值(max_bytes
、max_rows
、period
)时会在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
,它在 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 连接池的设置可能很有用。
此示例依赖于遗留的 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]
、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
数据类型尚未得到支持。
模拟
该 crate 提供了模拟 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 与我们联系。