ClickHouse 24.11.3.66 稳定版变更解析:强制合并增强、备份恢复提速与系统性故障修复
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
本篇文章围绕 ClickHouse 官方稳定分支的补丁版本 v24.11.3.66-stable(相较上一稳定版 v24.11.2.101-stable 的增量更新)展开,解读该版本引入的 1 项新特性、2 项改进与 19 项用户可见缺陷修复,并结合当前仓库源码(如 MergeTreeSettings.cpp、SimpleMergeSelector.cpp、StorageSystemMutations.cpp)说明其底层原理。读完你将掌握该版本的完整变更清单、每个修复背后的机制、以及升级前需要关注的行为变化。
版本概况
v24.11.3.66-stable 是 ClickHouse 24.11 稳定分支上的一个维护型补丁版本,其变更集全部通过 backport 机制从主分支回移而来。与上一稳定版 v24.11.2.101-stable 相比,本版本不包含破坏性变更,变更内容按类别划分为:
- New Feature(新特性):1 项,涉及强制合并策略的行为调整;
- Improvement(改进):2 项,涉及
system.mutations可观测性与RESTORE恢复性能; - Bug Fix(缺陷修复):19 项用户可见问题修复,覆盖 MergeTree 合并、备份恢复、动态列(Dynamic/JSON)、对象存储队列、访问控制、字典、分布式查询等多个子系统;
- NO CL ENTRY / NOT FOR CHANGELOG:若干内部重构与测试修复。
该版本的原始变更记录位于 v24.11.3.66-stable.md,属于 2025 年归档 Changelog 的组成部分(对应 docs/changelogs/archive 目录中的年度归档体系)。
新特性:强制合并可忽略最大字节限制
变更内容
本版本唯一的新特性(PR #73656)为:当min_age_to_force_merge_seconds与min_age_to_force_merge_on_partition_only同时启用时,part 合并将忽略max_bytes_to_merge_at_max_space_in_pool的字节上限限制。
在此之前,即便用户显式要求"把整个分区强制合并成一个 part",合并选择器仍会受背景合并池中单次合并的最大字节数约束,导致大分区无法被一次合并完毕,强制合并的目的无法达成。
底层实现原理
在 MergeTreeSettings.cpp 中可以看到这两个设置的定义:
min_age_to_force_merge_seconds(UInt64,默认 0):当范围内所有 part 的年龄都超过该阈值(秒)时执行合并;min_age_to_force_merge_on_partition_only(Bool,默认 false):上述年龄条件是否仅作用于整个分区(而非子集),用于"整个分区一次性合并成单个 part"。
合并选择器在 SimpleMergeSelector.cpp 的allow函数中实现了"年龄强制合并"判定:
if (settings.min_age_to_force_merge && min_age >= static_cast<double>(settings.min_age_to_force_merge)) return true;allow是合并是否被允许的核心判据。当年龄条件满足时直接返回true,意味着绕过了后续基于 size ratio 的常规合并判定。本版本在此基础上进一步调整:在min_age_to_force_merge_on_partition_only场景下,同时放宽max_bytes_to_merge_at_max_space_in_pool的约束,使整个分区能在一个合并任务中完成。
关联设置与使用建议
围绕该行为,仓库中还提供了两个密切相关的控制开关(定义于 MergeTreeSettings.cpp):
enable_max_bytes_limit_for_min_age_to_force_merge(Bool,默认 true):控制上述强制合并是否仍尊重max_bytes_to_merge_at_max_space_in_pool。本版本的变更即允许其生效路径被关闭,从而真正实现整分区合并;number_of_free_entries_in_pool_to_execute_optimize_entire_partition(UInt64,默认 25):当合并池中空闲条目低于该值时,不在后台执行"整个分区优化"任务,以保留空闲线程给常规合并,避免出现 "Too many parts"。
此外,仓库还提供了同族设置min_partition_age_to_force_merge_seconds(见 MergeTreeSettings.cpp),它用于"分区不再接收写入时按分区年龄强制合并",且每个合并仍尊重max_bytes_to_merge_at_max_space_in_pool。文档明确说明:在 Simple 与 StochasticSimple 合并选择器下,它不能与min_age_to_force_merge_seconds+min_age_to_force_merge_on_partition_only组合使用——因为只有"整分区一次合并"才会被标记为 final,从而允许ReplacingMergeTree执行CLEANUP。实践建议:分区能一次合并完用后一组设置,不能则用min_partition_age_to_force_merge_seconds。
验证此行为的单元测试位于 gtest_simple_merge_selector.cpp,其中直接引用了这些设置,是理解合并选择器行为边界的良好参考。
改进一:system.mutations新增错误码列
变更内容
PR #72398 为系统表system.mutations新增了latest_fail_error_code_name列,用于记录最近一次 part 变更(mutation)失败时异常对应的错误码名称。其动机是:为"卡住的 mutation"引入新监控指标,并基于错误构建图表,同时可选地添加噪声更低的告警。
实现细节
该列在系统表定义中声明(StorageSystemMutations.cpp):
{ "latest_fail_error_code_name", std::make_shared<DataTypeString>(), "The error code of the exception that caused the most recent part mutation failure." },底层状态结构在 MergeTreeMutationStatus.h 中新增字段String latest_fail_error_code_name = "";,并在查询时填充(StorageSystemMutations.cpp):
res_columns[col_num++]->insert(status.latest_fail_error_code_name);同时,该字段也被引入复制表(Replicated)的 mutation 队列结构(ReplicatedMergeTreeQueue.h),意味着复制表场景下 mutation 失败信息同样可被持久化并查询。
使用示例
SELECT database, table, command, latest_fail_error_code_name, is_done FROM system.mutations WHERE NOT is_done FORMAT Vertical;通过该列,运维人员可以在 mutation 长期不完成时直接看到失败的错误码名称(如资源不足、格式错误等),据此判断是否需要人工介入,或直接接入监控告警系统。
改进二:RESTORE 并行建表,加速大规模备份恢复
变更内容
PR #72427 实现了从备份恢复(RESTORE)时并行创建表。在此之前,RESTORE命令始终以单线程顺序创建表;当备份包含大量表时,这一阶段可能成为恢复流程的性能瓶颈。
源码佐证
并行恢复相关设置与元数据查找逻辑已体现在 BackupSettings.h 与 BackupMetadataFinder.h 中(这两个文件均包含与 parallel 相关的逻辑),配合 src/Backups 目录下完整的备份/恢复实现,可确认并行建表能力已内置于 24.11 稳定分支。
实践建议
- 对于包含成百上千张表的库级备份,升级到本版本后
RESTORE的建表阶段可显著缩短; - 若希望控制恢复期间的并发压力,可在恢复任务中显式设置并发相关的资源使用参数,观察
system.backups中的status与进度信息。
Bug Fix 全览:19 项用户可见问题修复
以下按子系统归类梳理本版本的修复项,便于按业务场景定位是否与自己相关。
MergeTree 合并、查询优化与 FINAL
- 修复
ALTER TABLE REPLACE/MOVE PARTITION FROM/TO TABLE后的暂停(PR #72024):该问题源于后台任务调度设置获取不正确,导致分区替换/移动操作后合并调度出现不必要的暂停; - 修复
FINAL+SAMPLE查询中的NOT_FOUND_COLUMN_IN_BLOCK(PR #73682):同时修复了在启用 FINAL 优化时从CollapsingMergeTree进行SELECT ... FINAL得到错误结果的问题; - 修复
LIMIT BY COLUMNS崩溃(PR #73686):LIMIT BY与COLUMNS表达式组合使用时的崩溃场景; - 修复投影(projection)中别名按逆序选择时未正确添加(PR #74033):当某别名被另一别名引用且按逆序选中时,别名可能无法被加入投影定义;
- 修复
parallel_replicas_for_non_replicated_merge_tree在子查询中被忽略(PR #73584):非复制 MergeTree 的并行副本设置在子查询中对非复制表不生效的问题。
动态列 Dynamic / JSON 与子列
- 修复 Dynamic/JSON 列 squashing 准备逻辑(PR #73388):此前即使类型/路径数量未达到限制,新类型也可能被错误地插入共享 variant/shared data;
- 修复 Dynamic 列的数据不一致(PR #73644):解决
Nested columns sizes are inconsistent with local_discriminators column size逻辑错误; - 修复 Dynamic/Object 结构反序列化(PR #73767):此前可能导致
CANNOT_READ_ALL_DATA异常; - 修复嵌套 Map 创建时的高内存占用(PR #73982);
- 修复
tupleElement函数错误(PR #73548):当元组包含LowCardinality元素且启用optimize_functions_to_subcolumns时可能出现的结果错误; - 修复从压缩的 Memory 引擎表读取子列时崩溃(PR #74161,对应 issue #74009)。
备份恢复与对象存储
- 恢复时跳过
metadata_version.txt(PR #73768):避免在从备份恢复 part 时处理该元数据文件引发问题; - 修复 S3 Express 支持(PR #73777,对应 issue #72078):S3 Express One Zone 存储此前在该版本分支上不可用;
- plain_rewritable 磁盘支持多实例共享(Azure)(PR #74059):使用 plain_rewritable 元数据的磁盘可在多个 server 实例间共享,初始化期间忽略对象未找到错误,与 S3 行为保持一致;
- 修复 ObjectStorageQueue 与 ZooKeeper/旧版 Keeper 的兼容问题(PR #73420)。
访问控制与字典
- 修复
REVOKE ALL ON *.*无法执行(PR #72872):目标访问实体中存在隐式授权(implicit grants)时导致的问题; - 修复字典数据源包含错误数据函数时的段错误(segfault)(PR #73535)。
查询解析、格式与表引擎
- 修复枚举 glob 后跟 range 的解析(PR #73569,对应 issue #73473);
EXPLAIN SYNTAX不再解释执行查询(PR #73634,对应 issue #65205):避免分布式查询因 processing stage 不一致产生逻辑错误;- TCPHandler 将 format 设置传播到 NativeWriter(PR #73179):确保
output_format_native_write_json_as_string等设置被正确应用; - 修复 Kafka 表引擎关键字参数解析(PR #74064);
- 修复 s3queue 中将文件标记为 failed 时的逻辑错误(PR #74216)。
内部变更与测试修复
除上述用户可见修复外,本版本还包含若干 NOT FOR CHANGELOG 级别变更:
- 修复线程池异常时
loadPathPrefixMap的 use-after-free(PR #72870); - 新增一项内部设置(PR #73281);
- 更新与修复
test_storage_s3_queue相关测试(PR #73607、#73632),涉及test_upgrade(2)与test_alter_settings; - 回退此前因 CI 崩溃引入的变更(PR #73738);
- 使
version_helper从每次提交均被填充(PR #74399)。
另外,本版本含一条 NO CL ENTRY 记录:回退了此前向 24.11 backport 的latest_fail_error_code_name列变更(PR #73974),即该改进在本版本中的落地经历了"添加—回退—再合入"的过程,最终以 #72398 的形式稳定合入,这也是为什么本文前述的源码与系统表中能看到该列已存在。
升级与验证建议
- 确认当前版本:执行
SELECT version()确认是否已低于 v24.11.3.66-stable,若处于同一 24.11 分支,可直接通过稳定版通道升级; - 关注合并行为变化:若你配置了
min_age_to_force_merge_seconds+min_age_to_force_merge_on_partition_only,升级后大分区合并可能一次性完成,注意监控合并池占用与磁盘 IO,可按需调整number_of_free_entries_in_pool_to_execute_optimize_entire_partition; - 验证 mutation 可观测性:升级后使用
DESCRIBE system.mutations或直接查询新增的latest_fail_error_code_name列,确认列可用并可接入监控; - 回归验证受影响场景:如果你使用了 Dynamic/JSON 列、
FINAL+SAMPLE、LIMIT BY COLUMNS、S3 Express 或从含大量表的备份执行RESTORE,建议在测试环境先行回归,再推广到生产。
总结
v24.11.3.66-stable 是 ClickHouse 24.11 稳定分支上一次聚焦"稳定与可观测性"的补丁发布:一方面通过min_age_to_force_merge族设置的组合行为调整增强了强制合并能力,另一方面通过system.mutations新增错误码列与RESTORE并行建表提升了运维可观测性与恢复性能;同时修复了横跨合并、动态列、备份恢复、访问控制、查询解析等多个子系统的 19 项缺陷。对于生产环境使用 24.11 分支的用户,本版本值得尽快跟进,相关行为变化与验证方法可参照上文逐一核对。
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考