资讯详情

ClickHouse v20.8.17.25-lts 维护版本解析:子查询常量折叠、ReplicatedMergeTree 变更同步与 ZooKeeper 请求稳定性修复

📅 2026/9/10 3:13:37 | 华诺云谱 👁 阅读
ClickHouse v20.8.17.25-lts 维护版本解析:子查询常量折叠、ReplicatedMergeTree 变更同步与 ZooKeeper 请求稳定性修复
ClickHouse v20.8.17.25-lts 维护版本解析子查询常量折叠、ReplicatedMergeTree 变更同步与 ZooKeeper 请求稳定性修复【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse本指南聚焦 ClickHouse 20.8 LTS 分支的维护版本 v20.8.17.25-lts 中三个关键修复点分析阶段子查询常量折叠的正确性修复、ReplicatedMergeTree 表引擎变更mutation/alter跨副本等待语义的修复以及 ZooKeeper 请求在 OOM 场景下可能挂起的问题。文章以官方变更记录为骨架结合当前仓库源码src/Interpreters/、src/Storages/、src/Common/ZooKeeper/验证实现细节帮助读者理解这些问题在什么场景下发生、修复如何落地以及如何通过配置规避相关风险。版本背景一次 LTS 分支的 Bug Fix 维护迭代v20.8.17.25-lts 是 ClickHouse 20.8 LTSLong Term Support系列中的维护版本其发布说明位于仓库的 docs/changelogs/archive/v20.8.17.25-lts.md。它基于上一版本 v20.8.16.20-lts 迭代而来变更内容集中在两个类别Bug Fix缺陷修复共 3 项涉及查询分析阶段的常量折叠、ReplicatedMergeTree 变更等待、ZooKeeper 请求挂起Build/Testing/Packaging Improvement构建/测试/打包改进共 1 项更新时区数据库timezones信息到 2020e。作为 20.8 分支的早期维护版本它体现了 LTS 分支“不引入新功能、只做稳定性和正确性修复”的迭代策略。20.8 是 ClickHouse 历史上首个 LTS 版本后续的 21.8、22.8 等 LTS 均沿用这一发布节奏。当时的维护版本尚未使用_lts之外的独立命名而是直接以.lts后缀标识。需要说明的是当前仓库/data/web/disk1/git_repo/GitHub_Trending/cli/ClickHouse的docs/changelogs/archive/目录下保存的是 ClickHouse 官方发布历史存档源码则为演进后的主线版本。因此下面用于佐证的源码可能包含较 20.8 更新的修改但其核心逻辑路径仍然成立且更能在“修复之后”的形态上说明问题的本质。修复一禁用子查询在分析阶段无法计算的常量折叠问题描述第一条修复对应官方 PR #18446指出在分析analysis阶段当子查询subquery的结果无法计算时必须禁用常量折叠constant folding。在 ClickHouse 中常量折叠是查询优化器的一项常见优化当一个表达式节点的所有子节点都能在分析期确定常量值时优化器会把该表达式直接折叠为一个常量COLUMN节点从而避免在运行期重复计算。然而当表达式涉及**标量子查询scalar subquery**时其值需要执行子查询才能得到。如果分析阶段出于某种原因无法执行该子查询例如子查询依赖的数据尚未就绪、或该子查询在分析期不可执行却仍然强行折叠就会得到错误的结果或产生异常。源码级验证常量折叠的开关路径在主线源码中常量折叠由ActionsDAGAction Directed Acyclic Graph动作有向无环图负责核心实现位于 src/Interpreters/ActionsDAG.cpp。removeUnusedActions系列函数接收allow_constant_folding参数只有在该参数为真时才执行折叠逻辑// src/Interpreters/ActionsDAG.cpp (主线形态) /// Constant folding. if (allow_constant_folding !node-children.empty() node-column) { node-type ActionsDAG::ActionType::COLUMN; node-children.clear(); node-is_deterministic_constant !non_deterministic_nodes.contains(node); }其语义是当一个节点的子节点都已变为常量node-column非空时将节点本身替换为COLUMN常量节点并清空其子节点从而在后续执行中直接使用常量值。而在 src/Interpreters/ExpressionAnalyzer.cpp 中allowEarlyConstantFolding()会先检查enable_early_constant_folding设置再遍历ActionsDAG节点判断是否存在不适合常量折叠的函数// src/Interpreters/ExpressionAnalyzer.cpp bool allowEarlyConstantFolding(const ActionsDAG actions, const Settings settings) { if (!settings[Setting::enable_early_constant_folding]) return false; for (const auto node : actions.getNodes()) { if (node.type ActionsDAG::ActionType::FUNCTION node.function_base) { if (!node.function_base-isSuitableForConstantFolding()) return false; } } return true; }对应地在 PREWHERE 表达式处理中代码明确以allow_constant_folding false调用removeUnusedActions因为“常量可能在查询的其他部分被使用不能在此处移除”// src/Interpreters/ExpressionAnalyzer.cppPREWHERE 构建路径 tmp_actions_dag.removeUnusedActions( NameSet{prewhere_column_name}, /* allow_remove_inputs */ true, /* allow_constant_folding */ false);这印证了 v20.8.17.25-lts 修复的思路在无法保证子查询可计算的分析阶段显式关闭常量折叠让子查询进入运行期正常执行而不是在分析期被错误折叠。对用户的影响与建议此问题通常不影响绝大多数查询但如果用户的查询在 WHERE/PREWHERE 中使用标量子查询、且子查询在分析期不可求值则升级到 v20.8.17.25-lts 后查询结果会更正确。相关可调设置enable_early_constant_folding布尔值默认开启在 src/Interpreters/ExpressionAnalyzer.cpp 中声明为SettingsBool如有必要可在服务端配置或查询级设置中关闭它。修复二ReplicatedMergeTree 变更操作跨副本等待语义问题描述第二条修复对应 PR #22669指出在多个副本上等待变更mutation完成时mutation/alter 查询可能在变更实际在其他副本执行完成之前就提前结束。ReplicatedMergeTree 是 ClickHouse 的复制表引擎其 DDL/DML 变更如ALTER TABLE ... UPDATE、DELETE、MODIFY COLUMN以 mutation 形式写入 ZooKeeper由各副本的 background 任务异步执行。当用户希望同步等待时通过mutations_sync设置对应早期版本的alter_sync控制等待行为。源码级验证waitMutation 的副本枚举逻辑修复后的等待逻辑位于 src/Storages/StorageReplicatedMergeTree.cpp 的waitMutation()// src/Storages/StorageReplicatedMergeTree.cpp void StorageReplicatedMergeTree::waitMutation(const String znode_name, size_t mutations_sync) const { if (!mutations_sync) return; /// we have to wait auto zookeeper getZooKeeper(); Strings replicas; /// Value 3 (wait only for active replicas) is a SharedMergeTree mode that ReplicatedMergeTree /// does not have; here it waits for all replicas, like value 2. if (mutations_sync 2 || mutations_sync 3) /// wait for all replicas { replicas zookeeper-getChildren(fs::path(zookeeper_path) / replicas); /// This replica should be first, to ensure that the mutation will be loaded into memory for (auto it replicas.begin(); it ! replicas.end(); it) { if (*it replica_name) { std::iter_swap(it, replicas.begin()); break; } } } else if (mutations_sync 1) /// just wait for ourself replicas.push_back(replica_name); waitMutationToFinishOnReplicas(replicas, znode_name); }关键点解读mutations_sync 0默认不等待变更异步执行查询立即返回mutations_sync 1只等待当前副本自身完成mutations_sync 2以及等价的 3等待所有副本完成先通过zookeeper-getChildren(.../replicas)枚举全部副本并确保当前副本排在列表首位以保证“mutation 先被当前副本加载进内存”这一前置条件若修复前枚举副本或判断完成条件的逻辑存在遗漏例如未正确等待所有副本就会出现“查询返回了但其他副本还没执行完变更”的一致性问题。此外同一文件中还有针对“在副本上发起同步变更”的防御性检查当mutations_sync 0且当前查询在某个副本上执行时会提示“同步 mutation 不受支持或可能导致挂起”建议改用mutations_sync 0或换到主节点发起// src/Storages/StorageReplicatedMergeTree.cpp if (query_context-getSettingsRef()[Setting::mutations_sync] 0 ...) { throw Exception( Synchronous mutation (mutations_sync {}) is not supported on a replica with the ..., ...); }mutations_sync本身是SettingsUInt64src/Storages/StorageReplicatedMergeTree.cpp可在查询级别使用SETTINGS mutations_sync N或全局配置指定。对用户的影响与建议若你的应用依赖“ALTER/MUTATION 完成后才继续”的强一致语义例如先改 schema 再写入应显式设置mutations_sync 2并升级到 v20.8.17.25-lts 及以上在设置同步等待时应通过system.mutations表观察变更进度注意同步等待会阻塞发起连接的查询线程变更量大时应评估耗时非复制场景MergeTree 引擎由IStorage::waitForMutationsrc/Storages/IStorage.cpp 中的空实现提供可结合MergeTreeSettings.cpp中的相关设置一起了解。修复三ZooKeeper 请求在 OOM 异常下的挂起问题问题描述第三条修复对应 PR #22684修复 issue #22438指出在 OOMOut Of Memory内存耗尽异常发生时ZooKeeper 请求可能出现挂起hang。ClickHouse 与 ZooKeeper或 KeeperClickHouse 自研的协调服务的交互通过ZooKeeper客户端完成。当内存受限、请求分配失败时如果客户端没有妥善处理异常路径请求可能永久阻塞在等待队列或 future 上进而拖垮依赖 ZooKeeper 的所有后台任务如复制队列、变更分发。源码级验证ZooKeeper 根节点检查不再挂起在 src/Common/ZooKeeper/ZooKeeper.cpp 中对 ZooKeeper root 存在性检查有一段与本次修复直接相关的注释// src/Common/ZooKeeper/ZooKeeper.cpp /// Here we check that zk root exists. /// This check is clumsy. The reason is we do this request under common mutex, and never want to hung here. /// Otherwise, all threads which need zk will wait for this mutex eternally. /// /// Usually, this was possible in case of memory limit exception happened inside zk implementation. /// This should not happen now, when memory tracker is disabled. /// But lets keep it just in case (it is also easy to backport). auto future asyncExists(/); auto res future.wait_for(std::chrono::milliseconds(args.operation_timeout_ms)); if (res ! std::future_status::ready) throw KeeperException::fromMessage(Coordination::Error::ZOPERATIONTIMEOUT, Cannot check if zookeeper root exists.);这段代码的要点该检查在公共互斥锁common mutex下执行如果阻塞等待没有超时保护所有需要 ZooKeeper 的线程都会等这把锁造成全局性挂起修复的关键是给future.wait_for加上operation_timeout_ms超时一旦超时未就绪立即抛出ZOPERATIONTIMEOUT异常而不是无限期等待注释明确说明该场景历史上正是由“zk 实现内部的内存限制memory limit异常”触发的——即 OOM 场景与 v20.8.17.25-lts 的修复描述完全对应修复在内存追踪器memory tracker禁用后虽然不再频繁触发但仍保留以增强健壮性并注明“易于 backport”说明其作为 20.8 维护修复被刻意保留为可移植形态。另外在 src/Common/ZooKeeper/IKeeper.h 中可以看到协调协议对内存限制的显式错误码// src/Common/ZooKeeper/IKeeper.h ZOUTOFMEMORY -10, /// Keeper has reached soft memory limit这从协议层印证了“协调服务自身也可能因达到软内存上限返回 OOM 类错误”的现实场景。对用户的影响与建议该修复面向所有通过ZooKeeper客户端与协调服务通信的表引擎复制表、ReplicatedMergeTree、分布式 DDL 队列等属于稳定性收益用户侧无需额外配置若曾在高内存压力下观察到“ZooKeeper 请求挂起、后台任务停滞”升级到 v20.8.17.25-lts 即可消除该类无限等待运维上仍应监控内存使用与operation_timeout_ms配置确保该超时值不过大以免掩盖协调服务异常。修复四时区数据库更新到 2020e第四条变更为构建/测试/打包类改进将 timezonesIANA 时区数据库信息更新到 2020e对应 PR #18531。时区数据影响所有与时区相关的日期时间函数与类型转换如toDateTime、timeZone()相关行为。2020e 版本包含该年度各国/地区关于夏令时调整和时区规则变更的最新信息。此更新通过contrib/下的 cctz 等时区组件随构建链编译进 ClickHouse属于“升级即生效”的改动无需额外配置。对于强时区敏感的业务如跨时区报表、定时任务建议关注后续 LTS 版本中持续更新的时区数据版本。升级建议与验证方式升级路径v20.8.17.25-lts 属于 20.8 LTS 分支的早期维护版本。若你当前运行在 20.8 分支的旧版本如 v20.8.16.20-lts 或更早可直接升级到该版本获得上述 3 项缺陷修复若运行在其他主版本请遵循对应 LTS 分支的迁移文档避免跨大版本直接升级带来的兼容性问题。验证方式变更等待修复对复制表执行ALTER TABLE ... UPDATE/DELETE ... SETTINGS mutations_sync 2观察语句返回后各副本system.mutations中对应 mutation 的is_done状态是否都已为 1常量折叠修复构造含标量子查询的 WHERE 条件查询确认结果正确且EXPLAIN输出中无异常提前折叠ZooKeeper 稳定性在高内存压力或降低 Keeper 内存上限的场景下观察复制队列任务是否仍能正常推进时区数据对比新老版本对特定夏令时日期如 2020 年规则变化涉及的日期的时区换算结果。小结v20.8.17.25-lts 作为 20.8 LTS 分支的维护版本体现了该分支“稳定优先、只修不增”的迭代哲学3 项缺陷修复分别覆盖查询优化正确性子查询常量折叠、复制表数据一致性变更跨副本等待、系统健壮性ZooKeeper OOM 挂起另有 1 项时区数据同步更新。结合当前仓库源码可以看到这些修复的落点分别是ActionsDAG的常量折叠开关、StorageReplicatedMergeTree::waitMutation的副本枚举与mutations_sync语义、以及ZooKeeper根检查的超时保护。对于运行 20.8 LTS 的用户本版本属于值得跟进的维护升级相关机制enable_early_constant_folding、mutations_sync、operation_timeout_ms在更新版本中继续沿用理解其语义有助于长期运维 ClickHouse 复制集群。延伸阅读仓库内资源变更记录原文docs/changelogs/archive/v20.8.17.25-lts.md常量折叠实现src/Interpreters/ActionsDAG.cpp、src/Interpreters/ExpressionAnalyzer.cpp变更等待与副本同步src/Storages/StorageReplicatedMergeTree.cpp、src/Storages/IStorage.cppZooKeeper 客户端与错误码src/Common/ZooKeeper/ZooKeeper.cpp、src/Common/ZooKeeper/IKeeper.h【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。