尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ClickHouse v20.10.3.30-stable 补丁版本解析:分布式查询、复制表指标与内存安全修复

ClickHouse v20.10.3.30-stable 补丁版本解析:分布式查询、复制表指标与内存安全修复 ClickHouse v20.10.3.30-stable 补丁版本解析分布式查询、复制表指标与内存安全修复【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouseClickHouse® 是一个面向实时分析场景的数据库管理系统其 v20.10.3.30-stable 是 v20.10 系列中的一个补丁版本在 v20.10.2.20-stable 基础上回填Backport了 1 项改进与 8 项 Bug 修复。本文以该版本官方 changelog 为骨架结合当前仓库源码逐条解析每个变更的触发场景、修复原理与配置方法帮助读者理解分布式表优化、复制表只读指标、内存安全等关键机制的实现细节。一、版本定位与变更总览1.1 版本号语义ClickHouse 的版本号遵循v主版本.次版本.补丁.构建号-稳定级别结构v20.10表示 2020 年 10 月发布的功能版本线.3.30表示该版本线内的第 3 个补丁版本构建号为 30-stable表示稳定发布分支变更均以 Backport从主干合入旧版本线方式进入风险可控。说明changelog 标题中保留了FIXME占位符v20.10.3.30-stable.md这是 ClickHouse 版本发布流程中用于标记待补全信息的内部标记不代表该版本存在问题。1.2 变更构成该版本包含 1 项改进Improvement与 8 项 Bug Fix涉及四大领域领域变更内容分布式查询优化新增allow_nondeterministic_optimize_skip_unused_shards设置修复dictGet在分片键中的持久上下文问题复制表Replicated修复 DETACH 只读表时ReadonlyReplica指标未递减的问题存储引擎健壮性数据部分part迁移到新磁盘/卷失败时支持重试DROP TABLE IF EXISTS与并发 DDL 的竞态修复内存与解析修复TwoLevelStringHashTable在GROUP BY字符串键场景的内存泄漏修复内存整体分配超限问题修复 collate/charset 解析器与String类型length0修复GROUP BY与TOTALS/ROLLUP/CUBE修饰符组合时的错误结果修复dictGet异常路径下的双重释放二、分布式查询改进允许非确定性函数参与分片跳过优化2.1 背景什么是 skip unused shards 优化对于Distributed表引擎查询下发时会根据WHERE/PREWHERE中作用于分片键sharding key的过滤条件提前判断哪些分片不可能命中数据并跳过从而减少网络开销与远端计算量。该能力由optimize_skip_unused_shards设置控制其官方语义为Enables or disables skipping of unused shards for SELECT queries that have sharding key condition inWHERE/PREWHERE, and activates related optimizations for distributed queries (e.g. aggregation by sharding key).该设置在 src/Core/Settings.cpp 中默认值为false0并明确警告该优化假设数据确实按分片键分布否则会产生错误结果。2.2 本版本的改进新增allow_nondeterministic_optimize_skip_unused_shards此前ClickHouse 出于正确性考虑只允许确定性函数如intHash64、cityHash64等出现在分片键中参与跳过优化——因为优化器需要把分片键表达式与查询条件做等价性匹配若分片键含rand()、dictGet()等非确定性函数无法安全推断“某分片不含目标数据”。本版本新增布尔设置allow_nondeterministic_optimize_skip_unused_shards默认false允许非确定性函数如rand()或dictGet()出现在分片键中。其设置定义位于 src/Core/Settings.cpp0默认— 不允许1— 允许。该设置的语义原文源码注释为Allow nondeterministic (likerandordictGet, since later has some caveats with updates) functions in sharding key.注意源码明确提示dictGet存在“与更新相关的注意事项”caveats with updates——字典更新后同一输入可能映射到不同分片因此启用该选项的查询结果可能与按旧字典值分片的数据不一致。2.3 源码实现确定性判定与三重使用点分片键的确定性是在表创建时静态计算的。在 src/Storages/StorageDistributed.cpp 的构造函数中if (sharding_key_) { ... sharding_key_expr buildShardingKeyExpression(...); ... sharding_key_is_deterministic isExpressionActionsDeterministic(sharding_key_expr); }即每个Distributed表在初始化时都会通过isExpressionActionsDeterministic定义见 src/Storages/StorageDistributed.cpp求出sharding_key_is_deterministic标志。此后所有依赖“分片键是否可用”的判断都采用同一个布尔表达式settings[Setting::allow_nondeterministic_optimize_skip_unused_shards] || sharding_key_is_deterministic该模式出现在三处关键位置查询处理阶段优化StorageDistributed.cppgetOptimizedQueryProcessingStageAnalyzer中optimize_sharding_key_aggregation只有在optimize_skip_unused_shards、optimize_distributed_group_by_sharding_key均开启、表有可读分片键且分片键确定性可用时才成立旧版查询路径StorageDistributed.cppgetOptimizedQueryProcessingStage采用完全相同的判定逻辑跳过未用分片StorageDistributed.cppsharding_key_is_usable判定后才会进入分片跳过逻辑。由此可见新设置的本质是当用户显式确认“我接受非确定性分片键带来的潜在数据分布不一致”就放开确定性约束让rand()/dictGet()分片键也能触发分片跳过与分组下推优化。2.4 配套修复dictGet在分片键中的函数上下文持久化同一版本还修复了与之强相关的 BugdictGet在 sharding_key及类似需要持久保存函数上下文的位置中的使用问题changelog 第 11 行。分片键表达式会被长期保存在表元数据中跨查询复用。此前dictGet等字典函数在“上下文持久存储”的场景下可能持有失效的外部字典句柄导致查询报错或结果异常。该修复PR #16205保证dictGet在 sharding_key 这种持久上下文中能正确解析并复用字典。2.5 配置示例与注意事项在config.xml的profiles段或用户级配置中启用profiles default optimize_skip_unused_shards1/optimize_skip_unused_shards allow_nondeterministic_optimize_skip_unused_shards1/allow_nondeterministic_optimize_skip_unused_shards /default /profiles或按会话设置SET optimize_skip_unused_shards 1; SET allow_nondeterministic_optimize_skip_unused_shards 1;实操注意点allow_nondeterministic_optimize_skip_unused_shards默认关闭且必须与optimize_skip_unused_shards配合才有意义若要强制优化必须生效否则报错可叠加force_optimize_skip_unused_shards设置定义于 src/Core/Settings.cpp取值为 0/1/2分别表示不强制、查询必须可跳过、以及可跳过与有分片键两个等级分片键含dictGet()且字典会在线更新LIFETIME刷新时跳过优化可能与实际数据分布不一致建议仅在不关心“字典更新瞬间的写入错位”时开启。三、Bug Fix 详解3.1 修复ReadonlyReplica指标在 DETACH 只读表时不递减问题现象当一个ReplicatedMergeTree表因 ZooKeeper 会话丢失、或未配置 ZooKeeper 启动而进入只读readonly状态时ReadonlyReplica指标会递增。但此前若直接对这只读表执行DETACH或DROP指标不会递减导致system.metrics中ReadonlyReplica计数虚高且长期无法归零对应 issue #15598。指标定义位于 src/Common/CurrentMetrics.cppReadonlyReplica当前由于 ZooKeeper 会话丢失后重新初始化、或因未配置 ZooKeeper 启动而处于只读状态的 Replicated 表数量。修复原理本版本的修复PR #15592在表的 DETACH/DROP 路径上补充了指标递减。从源码看该指标的管理集中在 ReplicatedMergeTreeRestartingThread.cpp 的setReadonly/setNotReadonly中setReadonly(true)完整关闭场景时不再递增指标——因为纯关闭不构成“只读表”表已是只读、且再次进入关闭流程on_shutdowntrue时会通过std::exchange(storage.is_readonly_metric_set, false)判断指标是否此前已设置若已设置则执行CurrentMetrics::sub(CurrentMetrics::ReadonlyReplica)见 ReplicatedMergeTreeRestartingThread.cpp——这正是本次修复的落点DETACH/DROP 只读表时正确递减指标setNotReadonly()中由于启动时只读态并不会递增指标启动成功就不算只读因此仅在指标确已设置时才sub第 447-451 行并用chassert保证指标不为负。在 StorageReplicatedMergeTree.cpp 的startupImpl中当 ZooKeeper 未配置或无元数据时会通过std::exchange(is_readonly_metric_set, true)仅递增一次指标配合上述递减逻辑形成完整的“递增/递减”闭环。运维启示升级到该版本后如果此前ReadonlyReplica指标长期偏高可在 DETACH 并重新 ATTACH 只读副本后观察指标回落该指标也可用于告警——持续非零往往意味着副本与 ZooKeeper 失联。3.2 数据部分迁移失败后的重试问题现象在使用多卷volume/多磁盘存储策略如冷热分层时把 part 从旧磁盘迁移到新磁盘/卷的第一次尝试若失败如目标磁盘瞬时不可用此前该 part 不会重试迁移导致数据滞留或任务中断对应 issue #16177。修复PR #15723 使 part 迁移在首次尝试失败后具备再次迁移的可能性提升了存储策略storage policy分层迁移的容错性。多卷策略的配置方式可参考 StorageDistributed.cpp 中对多 volume 的警告处理——虽然该处针对 Distributed 表但其揭示的存储策略机制同样适用于 MergeTree 系策略中首个 volume 存放数据多 volume 时后续 volume 会被忽略并记录警告。对于需要迁移数据的场景应通过ALTER TABLE ... MOVE PART ... TO DISK/VOLUME或在MergeTree设置中配置 TTL 策略触发。3.3 Atomic 数据库引擎下并发 DDL 的竞态修复问题现象对应 issue #16323以下并发场景出现错误或死锁DROP TABLE IF EXISTS在表被并发重命名时仍报Table ... doesnt exist并发执行涉及多表的 DDL如DROP DATABASE与RENAME TABLE时出现罕见死锁DROP/DETACH DATABASE与并发DROP/DETACH TABLE交替执行时报Table ... doesnt exist。修复PR #15934 统一了 Atomic 数据库引擎下 DDL 与表/库元数据操作的同步逻辑保证IF EXISTS语义在重命名竞态下仍成立并消除了多表 DDL 间的死锁窗口。这属于数据库内核元数据层的并发正确性修复升级即可生效无需配置。3.4 collate/charset 名称解析与String类型length0支持修复内容PR #16008两个关联问题——一是修复 collate 名称与 charset 名称的解析器使其能正确处理带引号或特殊字符的名称二是允许String类型声明length 0。从类型系统看String在 ClickHouse 中是不定长二进制串其序列化层 SerializationString.cpp 中定义了硬上限MAX_STRING_SIZE 16_GiB见 SerializationString.h读取时超过该上限即抛异常。修复前解析器对String(0)这类显式零长度声明处理不当修复后可按长度参数声明使用实际长度仍不受该声明约束仅用于语法兼容与元数据记录。collate 解析的修复影响ORDER BY ... COLLATE等排序相关语法相关 AST 见 ASTOrderByElement.cpp 与 ASTColumnDeclaration.cpp确保带引号的 collation 名称能被正确识别。3.5 修复内存整体分配超限问题现象对应 issue #14560在某些分配路径上即使设置了内存限制进程仍可能“整体过量分配”memory can be overallocated regardless to the limit——即实际使用内存可绕过限制。修复PR #16206 修正了内存跟踪memory tracking与限制判定路径使分配超限检测在所有分配入口保持一致。ClickHouse 的内存管理以CurrentMetrics和MemoryTracker为核心任何查询与后台任务都会计入限制此类修复通常不改变对外配置而是收紧内部计数逻辑。运维上可继续通过max_memory_usage等配置控制单查询内存并通过system.metrics、system.processes观测实际使用量是否与限制吻合。3.6 修复TwoLevelStringHashTable在GROUP BY字符串键下的内存泄漏问题现象使用字符串键执行GROUP BY当哈希表增长到二级two-level结构时TwoLevelStringHashTable实现中的一个错误可能导致内存泄漏对应 PR #16264。源码结构TwoLevelStringHashTable定义于 src/Common/HashTable/TwoLevelStringHashTable.h它按哈希值高 8 位BITS_FOR_BUCKET 8见 第 5 行 与getBucketFromHash把元素分散到 256 个子表impls其size()、getBufferSizeInBytes()等均对子表求和第 174-196 行。字符串哈希表底层为 StringHashTable.h析构为default见 第 355 行元素生命周期依赖容器正确的清理/重建逻辑。本次修复PR #16264作者 Amos Bird修正了该实现中的清理路径避免长时间运行的GROUP BY字符串聚合查询持续增长内存。运维启示若观察到带字符串键的大GROUP BY查询内存随时间单调上涨可升级该版本验证是否由本 Bug 引起同时可借助system.query_log的memory_usage字段对比修复前后的内存峰值。3.7 修复GROUP BY与TOTALS/ROLLUP/CUBE修饰符下的错误结果问题现象对应 issue #16393当查询使用GROUP BY ... WITH TOTALS、WITH ROLLUP或WITH CUBE修饰符且聚合函数为作用于分组键的min/max例如GROUP BY city WITH TOTALS同时SELECT min(city)时可能返回错误结果。修复PR #16397 修正了分组键在修饰符展开总行/小计/立方体行过程中的取值逻辑。注意 StorageDistributed.cpp 的注释 也印证了这类修饰符的复杂性——分布式查询优化中WITH TOTALS/WITH ROLLUP甚至被标记为“TODO未来可能实现”可见其正确处理涉及多处代码路径。升级后建议对线上TOTALS/ROLLUP/CUBE查询做一次结果回归校验。3.8 修复dictGet异常路径下的双重释放问题现象若字典加载过程出错dictionary was loaded with errordictGet函数在异常路径上可能触发双重释放double free导致进程崩溃或内存破坏对应 PR #16448。修复PR #16429 在dictGet的异常处理分支中修正了资源所有权确保无论字典加载成功与否缓存与外部字典对象的释放次数严格为一次。该修复与第 2.4 节的dictGet上下文持久化修复同属一个主题线均由字典函数在分布式/持久场景下的状态管理引发一起升级可获得完整修复。四、升级建议与验证清单升级路径v20.10.3.30-stable 为补丁版本可平滑替换同系列 v20.10.2.20-stable跨大版本升级请先查阅 CHANGELOG.md 与对应版本的 changelogs 归档 确认兼容性。重点回归场景使用了rand()/dictGet()分片键的Distributed表验证第 2 节新设置依赖ReadonlyReplica指标做告警的环境验证 DETACH 后指标归零见第 3.1 节大量字符串键GROUP BY的长任务验证内存是否稳定见第 3.6 节WITH TOTALS/ROLLUP/CUBE聚合查询验证结果正确性见第 3.7 节。配置影响除新增的allow_nondeterministic_optimize_skip_unused_shards外其余修复均为代码级修复无需修改既有配置新设置默认关闭不会改变现有行为。【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表