ClickHouse v20.5.2.7-stable 发布说明解析:DROP REPLICA 副本清理、分布式副本容错与关键缺陷修复
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
本篇文章以 ClickHouse v20.5.2.7-stable 的官方发布说明为骨架,逐条解析该版本引入的新特性、行为改进、缺陷修复与构建优化,并结合仓库源码说明其底层实现机制。读完本文,你将掌握该版本中ALTER TABLE ... DROP REPLICA的副本清理能力、分布式表副本选择时的容错参数配置方法,以及一批影响查询正确性与稳定性的关键修复背后的原理。
版本背景与定位
v20.5.2.7-stable 是 ClickHouse 20.5 分支上的一个 stable(稳定版)补丁版本,基于更早的 v20.5.1.3833-prestable 版本之上。它的意义在于:把一批在 prestable(预稳定)阶段经过验证的新特性、行为改进与 Bug 修复固化到 stable 分支,供生产环境安全使用。
从发布说明的分类来看,该版本的工作集中在以下四个方向:
- 新特性:为复制表增加
DROP REPLICA能力; - 行为改进:分布式副本容错、ODBC 连接串兼容、MySQL 类型修饰符兼容、聚合函数能力扩展等;
- 缺陷修复:涉及查询正确性、内存统计、崩溃防护、访问控制等 7 项;
- 构建/测试/打包改进:面向 serverless、Android 等运行环境。
下文按发布说明的原始分类逐项展开。
新特性:ALTER TABLE ... DROP REPLICA
发布说明中的第一项新特性是:
Add
Alter table drop replica replica_namesupport.
该特性解决了 ReplicatedMergeTree 副本生命周期管理中的一个实际痛点:当某个副本服务器被彻底销毁、其元数据残留在 ZooKeeper 中且无法通过常规DROP TABLE清理时,需要一种手段直接从 ZooKeeper 中移除残留的副本路径。
底层实现
从当前仓库源码看,该能力对应StorageReplicatedMergeTree::dropReplica的实现(src/Storages/StorageReplicatedMergeTree.cpp),其核心步骤是:
- 会话有效性检查:若 ZooKeeper 会话已过期(
zookeeper->expired()),直接抛出异常,避免在不可靠会话上执行破坏性操作; - 标记为 lost:在删除前先将副本节点下的
is_lost标记置为"1"。注释明确说明这是为了防止递归删除过程中失败时,部分删除的副本仍可能被视为存活节点; - 幂等性保证:如果副本路径已不存在,则直接返回
false,保证重复执行DROP REPLICA不会报错; - 分层删除:先移除
host节点(作为“副本已被删除”的标记,选择它是因为该节点自远古版本起就存在且不会被启动流程重建),随后删除flags、queue等扁平节点,以及(在开启use_minimalistic_part_header_in_zookeeper时的)parts节点。
与 SYSTEM DROP REPLICA 的关系
值得注意的是,ALTER TABLE ... DROP REPLICA并非唯一入口。仓库解析器中还提供了一整套SYSTEM DROP REPLICA语法族(src/Parsers/ParserSystemQuery.cpp):
SYSTEM DROP REPLICA 'replica_name' FROM TABLE database.table; SYSTEM DROP REPLICA 'replica_name' FROM DATABASE database; SYSTEM DROP REPLICA 'replica_name'; SYSTEM DROP REPLICA 'replica_name' FROM ZKPATH '/path/to/table/in/zk';官方说明(见 src/Parsers/ASTSystemQuery.cpp)指出:这类查询用于移除 ZooKeeper 中ReplicatedMergeTree的副本路径,适用于副本已死且其元数据无法由DROP TABLE清除的场景——因为本地已不存在对应表。它只会删除非活跃/过期的副本,且不能删除本地副本(本地副本请使用DROP TABLE);DROP REPLICA不会删除任何本地表、数据和磁盘上的元数据。
因此ALTER TABLE ... DROP REPLICA与SYSTEM DROP REPLICA是同一底层能力在 SQL 语法层两种形态,前者从表对象维度触发,后者可从表、数据库或裸 ZooKeeper 路径维度触发。从发布说明看,v20.5.2.7-stable 先把ALTER TABLE形态引入,之后系统级语法族才逐步补全。
改进一:分布式表副本选择容错(distributed_replica_error_ignore)
发布说明中的第二项改进:
Add number of errors to ignore while choosing replicas (
distributed_replica_error_ignore).
这为Distributed表引擎在选择副本时引入“可忽略错误数”的概念。在分布式查询执行中,当某个副本连续出错时,ClickHouse 会依据错误计数决定是否继续向该副本发送查询(配合load_balancing算法)。该设置允许管理员指定一个阈值:在阈值范围内的错误次数将被容忍,副本仍可参与选择,从而避免因偶发瞬时错误导致副本被过早“下线”。
当前源码中的对应参数
从当前仓库源码看,该能力对应的设置项在 src/Core/Settings.cpp 中定义为:
distributed_replica_max_ignored_errors - Type: unsigned int - Default value: 0其语义为“在选择副本时(依据load_balancing算法)将被忽略的错误数量”。与它协同工作的还有两个参数(src/Core/Settings.cpp):
| 设置项 | 类型 | 默认值 | 作用 |
|---|---|---|---|
distributed_replica_error_half_life | Seconds | 连接池默认错误衰减周期 | 控制分布式表错误计数的衰减速度。例如副本累计 5 个错误、half_life 为 1 秒时,最后一次错误后约 3 秒副本即被视为恢复正常 |
distributed_replica_error_cap | UInt64 | 连接池最大错误数上限 | 错误计数上限,防止计数无限增长 |
需要说明的是,发布说明中的参数名为distributed_replica_error_ignore,而当前仓库中已更名为distributed_replica_max_ignored_errors(默认值 0)。可以推断这是后续演进中对参数命名的规范化,语义一脉相承:默认不忽略任何错误,管理员可结合实际故障容忍需求调大该值。
典型配置场景
该能力适合多副本分布式集群中“少量副本短时抖动”的场景:
-- 选择副本时最多忽略 2 次历史错误 SET distributed_replica_max_ignored_errors = 2; -- 让错误计数更快衰减(例如 30 秒半衰期) SET distributed_replica_error_half_life = 30; -- 限制错误计数上限 SET distributed_replica_error_cap = 100;注意:这些参数为会话级/查询级设置,也可写入服务端配置或用户配置文件以全局生效。
改进二:无结构锁存储的多版本元数据(Multiversion metadata)
Multiversion metadata for storages without structure locks.
该改进针对不使用传统结构锁(structure locks)的存储引擎,引入多版本元数据机制。其意义在于:在没有全局结构锁保护的情况下,读取路径需要一种“快照式”地访问元数据的方式,避免在元数据变更(如 ALTER)过程中读到不一致的中间状态。这是 ClickHouse 在弱锁化、高并发路径上持续推进的一部分——通过多版本化,读操作可以始终基于某个一致的元数据版本执行,写路径则发布新版本,从而在不引入全局锁开销的前提下保证元数据读写的正确性。
改进三:放宽 ODBC 连接串验证
Slightly relax the validation of ODBC connection string. If the hostname or username contains only word characters along with
.and-, don't put it into curly braces.
该改进放宽了 ODBC 连接字符串的校验规则:当主机名或用户名只包含单词字符以及.和-时,不再将其包裹进花括号{}。原因在于部分 ODBC 驱动(如 PostgreSQL 的驱动)无法理解被花括号包裹的主机名。这一调整提升了 ClickHouse ODBC 表函数与外部数据库(尤其是 PostgreSQL)对接时的兼容性,属于典型的“小改动解决真实兼容问题”。
改进四:支持标准整型的 SIGNED / UNSIGNED 修饰符
Support
SIGNEDandUNSIGNEDmodifiers of standard integer types (BIGINT,INT, ...) for compatibility with MySQL.
该改进使 ClickHouse 在解析标准整数类型(BIGINT、INT等)时接受 MySQL 风格的SIGNED/UNSIGNED修饰符。例如:
CREATE TABLE t (a BIGINT SIGNED, b INT UNSIGNED) ENGINE = MergeTree ORDER BY a;这一语法兼容性让从 MySQL 迁移的 SQL 脚本可以不加修改地运行。从实现层面看,这类修饰符在解析阶段被识别后,会映射到 ClickHouse 对应的无符号整数类型(如UInt64、UInt32等),即“语法上兼容 MySQL,语义上落到原生类型系统”。
改进五:sumWithOverflow 支持 SimpleAggregateFunction
Allow to use
sumWithOverflowasSimpleAggregateFunction.
SimpleAggregateFunction是 ClickHouse 对简单聚合(可增量、状态可折叠的聚合)的优化:它把聚合函数状态直接存储在列中,免去复杂状态序列化开销。此前sumWithOverflow(溢出时按目标类型回绕的求和聚合,而非抛异常)不能被用作SimpleAggregateFunction,该版本解除此限制。典型用法:
CREATE TABLE events ( id UInt64, cnt SimpleAggregateFunction(sumWithOverflow, UInt64) ) ENGINE = AggregatingMergeTree ORDER BY id;该改进让需要在聚合状态中容忍整数回绕的计数类场景也能享受AggregatingMergeTree/SimpleAggregateFunction的存储与合并优化。
改进六:哈希函数支持 FixedString
Add FixedString support in Hashing functions.
该版本为各类哈希函数(如cityHash64、sipHash64等)补齐了FixedString类型的支持,使定长二进制字符串能够直接参与哈希计算,不再需要先转换类型。对于以定长 ID 或哈希值(如FixedString(16)存储的 UUID 二进制形态)作为输入的分析场景,这是直接的可用性提升。
Bug 修复:查询正确性与稳定性修复清单
v20.5.2.7-stable 共修复 7 项缺陷,按影响面可分为三类。
查询解析与结果正确性
- 修复
SELECT *, xyz.*被错误接受:此前形如SELECT *, xyz.*的查询本应报错(通配符与其他列表达式混用规则不允许),却被意外放行并返回结果;该版本改为正确报错。 - 修复
if()条件含 NULL 时的错误结果:当if(cond, a, b)的cond为Nullable类型且取值为NULL时,此前可能返回错误分支值;修复后NULL条件按假值处理,结果符合 SQL 语义。 - 修复含
Nullable列的元组比较错误:对包含Nullable列的元组执行比较运算(如(a, b) > (c, d))时结果可能不正确,该版本修复了这类比较的求值逻辑。
崩溃与异常防护
- 修复 prewhere 中使用
Nullable列导致的偶发崩溃:该问题源于更早的一个已知问题(issue 11608)的延续,在PREWHERE优化路径中处理Nullable列时可能触发段错误,修复后不再崩溃。 - 修复解析 DateTime64 时的潜在浮点异常:解析
DateTime64字符串的代码路径中存在异常分支,可能触发浮点除零(FPE),进而导致进程崩溃。该版本修正了 DateTime64 解析逻辑,保证极端输入下进程稳定。
内存统计与访问控制
- 修复 HTTP 接口的内存统计错误:在使用 HTTP 接口且开启
wait_end_of_query=1时,内存计数可能出现显著偏差,导致内存使用被误报或限额判断失准;修复后内存统计与真实分配保持一致。 - 修复
USE database后访问权限检查使用错误数据库:执行USE database之后,后续语句的权限检查此前可能仍沿用旧的当前数据库,导致误放行或误拒绝;修复后权限检查基于USE之后的新当前库执行。
实战建议
如果生产环境使用 20.5 分支并遇到以下现象,建议优先升级到 v20.5.2.7-stable 或更新的补丁版本:
PREWHERE配合Nullable列时偶发崩溃;- 解析异常的
DateTime64文本时进程异常退出; - HTTP 长查询(
wait_end_of_query=1)时内存统计异常; - 含
Nullable列的元组/if()查询结果不一致。
构建 / 测试 / 打包改进
该版本在工程侧有三项改进:
- 新增 serverless 环境的 GitHub hook 脚本:为 serverless(无服务器)CI 场景补充了简易的 GitHub 事件钩子脚本,便于在事件驱动环境中触发构建与测试任务;
- 致命错误时向客户端发送日志:当服务端发生致命错误(fatal error)时,尽可能将日志推送给客户端,显著提升测试结果与线上问题的可读性,避免只能事后翻看服务端日志;
- 支持在 Android 上运行 ClickHouse:打通了 Android 平台的构建与运行支持,使得 ClickHouse 的可执行文件可以在 Android 环境(如 Termux 类环境)中运行,面向移动端分析场景。
附加说明:NO CL ENTRY
发布说明末尾标注了两条 “NO CL ENTRY” 记录,它们不是功能变更,而是合入过程中的元数据说明——一条对应DROP REPLICA特性合入时的合并记录,另一条对应 DateTime64 修复的 20.5 分支 cherry-pick 记录。这类条目是 ClickHouse 变更日志的常态,不影响版本行为。
总结
v20.5.2.7-stable 是一个小而精的稳定版补丁:
- 能力上,为复制表引入了
DROP REPLICA清理机制(对应 src/Storages/StorageReplicatedMergeTree.cpp 中的dropReplica实现),并完善了分布式表的副本选择容错(对应 src/Core/Settings.cpp 中的distributed_replica_max_ignored_errors); - 兼容性上,补齐了 MySQL 的
SIGNED/UNSIGNED修饰符与 ODBC 连接串规则,降低了迁移与外部对接成本; - 稳定性上,修复了 prewhere/
Nullable崩溃、DateTime64 解析异常、HTTP 内存统计偏差等 7 项缺陷,值得 20.5 分支用户优先跟进。
如需深入验证本文涉及的实现细节,可继续查阅仓库中的 StorageReplicatedMergeTree.cpp、ParserSystemQuery.cpp 与 Settings.cpp。
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考