ClickHouse Rust 客户端
用于连接 ClickHouse 的官方 Rust 客户端,最初由 Paul Loyd 开发。客户端源代码可在 GitHub 仓库 中获取。
概述
- 使用
serde
进行行的编码/解码。 - 支持
serde
属性:skip_serializing
、skip_deserializing
、rename
。 - 使用
RowBinary
格式通过 HTTP 进行传输。- 计划切换到通过 TCP 的
Native
格式。
- 计划切换到通过 TCP 的
- 支持 TLS(通过
native-tls
和rustls-tls
功能)。 - 支持压缩和解压缩(LZ4)。
- 提供选择或插入数据、执行 DDL 和客户端批处理的 API。
- 提供便捷的模拟工具用于单元测试。
安装
要使用该 crate,请将以下内容添加到您的 Cargo.toml
:
另请参见:crates.io 页面。
Cargo 特性
lz4
(默认启用)— 启用Compression::Lz4
和Compression::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-tls
或 rustls-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-tls
或 native-tls
cargo 特性。
然后,像往常一样创建客户端。在此示例中,环境变量用于存储连接详细信息:
URL 应包含协议和端口,例如 https://instance.clickhouse.cloud:8443
。
另请参见:
- 具有 ClickHouse Cloud 的 HTTPS 示例 在客户端仓库中。这同样适用于本地 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 异步插入 来避免客户端对传入数据的批处理。这可以通过简单地向 insert
方法(甚至直接向 Client
实例)提供 async_insert
选项来完成,这样它会影响所有 insert
调用。
另请参见:
- 异步插入示例 在客户端仓库中。
插入器功能(客户端批处理)
需要 inserter
cargo 特性。
Inserter
如果达到任何阈值(max_bytes
、max_rows
、period
),则在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
外,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
目前不直接支持,但有 解决方案。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
通过使用serde::ipv4
映射到std::net::Ipv4Addr
。
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)
,其余类型仅是点的切片。
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
数据类型尚未支持。- 服务器端参数绑定尚未支持;有关跟踪的请参见 此问题。