概述
- 使用
serde对行进行编码和解码。 - 支持
serde属性:skip_serializing、skip_deserializing、rename。 - 通过 HTTP 传输使用
RowBinary格式。- 计划切换为通过 TCP 使用
Native。
- 计划切换为通过 TCP 使用
- 支持 TLS (通过
native-tls和rustls-tls功能) 。 - 支持压缩和解压缩 (LZ4) 。
- 提供用于查询或插入数据、执行 DDL 语句以及客户端批处理的 API。
- 为单元测试提供便捷的模拟对象 (mocks) 。
安装
Cargo.toml 中:
Cargo 特性
lz4(默认启用) — 启用Compression::Lz4和Compression::Lz4Hc(_)变体。启用后,除WATCH外,所有查询默认使用Compression::Lz4。native-tls— 通过hyper-tls支持使用HTTPSschema 的 URL,并会链接到 OpenSSL。rustls-tls— 通过hyper-rustls支持使用HTTPSschema 的 URL,且不会链接到 OpenSSL。inserter— 启用client.inserter()。test-util— 添加 mock。请参见该示例。仅在dev-dependencies中使用。watch— 启用client.watch功能。详见对应章节。uuid— 添加serde::uuid以便与 uuid crate 配合使用。time— 添加serde::time以便与 time crate 配合使用。
ClickHouse 版本兼容性
wa-37420 feature 来解决此问题。注意:不要将此 feature 与较新的 ClickHouse 版本一起使用。
示例
用法
ch2rs crate 可用于根据 ClickHouse 生成行类型。
创建客户端实例
HTTPS 或 ClickHouse Cloud 连接
rustls-tls 或 native-tls cargo feature 配合使用。
然后,像平常一样创建客户端。在此示例中,使用环境变量来存储连接信息:
- 客户端仓库中的 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 选项也可能会有帮助。
插入行
- 如果未调用
end(),此次INSERT将被中止。 - 行会以 stream 的形式逐步发送,以分摊网络负载。
- 只有当所有行都属于同一分区,且行数小于
max_insert_block_size时,ClickHouse 才会以原子方式插入整个批次。
异步插入 (服务端批处理)
insert 方法传入 async_insert 选项即可 (甚至可以直接在 Client 实例上设置,这样会影响所有 insert 调用) 。
- 客户端仓库中的 async insert 示例。
Inserter 功能 (客户端批量处理)
inserter Cargo 功能。
- 当任一阈值 (
max_bytes、max_rows、period) 达到时,Inserter会在commit()中结束当前正在进行的插入。 - 可以使用
with_period_bias调整相邻两次结束活动INSERT的时间间隔,以避免并行 inserter 带来的负载尖峰。 Inserter::time_left()可用于判断当前周期何时结束。如果你的 stream 很少发出条目,请再次调用Inserter::commit()以检查这些限制。- 时间阈值通过 quanta crate 实现,以加快
inserter的运行速度。如果启用了test-util,则不会使用它 (因此在自定义测试中可以通过tokio::time::advance()控制时间) 。 - 两次
commit()调用之间的所有行都会通过同一条INSERT语句插入。
执行 DDL 语句
wait_end_of_query 选项,等待 DDL 在所有副本上应用完成。可以这样做:
ClickHouse 设置
with_option 方法应用各种 ClickHouse 设置。例如:
query 之外,insert 和 inserter 方法的用法也类似;此外,也可以在 Client 实例上调用同一方法,为所有查询设置全局参数。
查询 ID
.with_option,可以设置 query_id 选项,用于在 ClickHouse 查询日志中标识查询。
query,它与 insert 和 inserter 方法的用法也类似。
如果手动设置
query_id,请确保其唯一。UUID 是不错的选择。会话 ID
query_id 类似,你也可以设置 session_id,以便在同一会话中执行这些语句。session_id 既可以在客户端级别进行全局设置,也可以为每次 query、insert 或 inserter 调用单独设置。
在集群部署中,由于缺少”会话粘性”,你需要连接到特定的集群节点,才能正确使用此功能。因为例如轮询负载均衡器无法保证后续请求会由同一个 ClickHouse 节点处理。
自定义 HTTP 请求头
自定义 HTTP 客户端
数据类型
另请参阅以下补充示例:
(U)Int(8|16|32|64|128)可与对应的(u|i)(8|16|32|64|128)类型或基于它们定义的 newtype 相互映射。(U)Int256不直接受支持,但有一种变通方法。Float(32|64)可与对应的f(32|64)或基于它们定义的 newtype 相互映射。Decimal(32|64|128)可与对应的i(32|64|128)或基于它们定义的 newtype 相互映射。使用fixnum或其他有符号定点数实现会更方便。Boolean可与bool或基于它定义的 newtype 相互映射。String可与任意字符串或字节类型相互映射,例如&str、&[u8]、String、Vec<u8>或SmartString。也支持 newtype。若要存储字节,建议使用serde_bytes,因为它的效率更高。
FixedString(N)支持表示为字节数组,例如[u8; N]。
- 可通过
serde_repr支持Enum(8|16)。
UUID可通过serde::uuid与uuid::Uuid相互映射。需要启用uuid特性。
IPv6可与std::net::Ipv6Addr相互映射。IPv4可通过serde::ipv4与std::net::Ipv4Addr相互映射。
Date可映射为/从u16或其包装的 newtype,表示自1970-01-01起经过的天数。此外,也支持time::Date,可通过serde::time::date使用,但需要启用timefeature。
Date32可映射为/从i32或其对应的 newtype 映射而来,表示自1970-01-01以来经过的天数。此外,还支持time::Date,可通过serde::time::date32使用,但这需要启用timefeature。
DateTime可与u32或其封装 newtype 相互映射,表示自 UNIX 纪元以来经过的秒数。此外,还可通过serde::time::datetime支持time::OffsetDateTime,但这需要启用timefeature。
DateTime64(_)可映射为/从i32或其外层 newtype,并表示自 UNIX 纪元以来经过的时间。另请注意,也支持time::OffsetDateTime:使用serde::time::datetime64::*即可,但这需要启用timefeature。
Tuple(A, B, ...)可映射为/从(A, B, ...),也可映射为其外层的 newtype。Array(_)可映射为/从任意切片,例如Vec<_>、&[_]。也支持 newtype。Map(K, V)的行为类似Array((K, V))。LowCardinality(_)可无缝使用。Nullable(_)可映射为/从Option<_>。对于clickhouse::serde::*辅助函数,请添加::option。
Nested可通过提供多个数组并进行重命名来支持。
- 支持
Geo类型。Point的行为类似于元组(f64, f64),其余类型都只是点切片。
Variant、Dynamic和 (新的)JSON数据类型目前尚不支持。
模拟
SELECT、INSERT 和 WATCH 查询。可通过 test-util feature 启用此功能。仅应将其用作开发依赖。
参见示例。
故障排查
CANNOT_READ_ALL_DATA
CANNOT_READ_ALL_DATA 错误最常见的原因是应用程序端的行定义与 ClickHouse 中的定义不一致。
请看下面这张表:
EventLog 类型不一致,例如:
EventLog 结构体来解决:
已知限制
- 目前尚不支持
Variant、Dynamic和 (新的)JSON数据类型。 - 目前尚不支持服务端参数绑定;相关进展请参见此 issue。