资讯详情

ClickHouse v25.8.6.11-lts 发布解析:路径包含判断、Mutation Patch 与 EmbeddedRocksDB 等五处修复的源码级解读

📅 2026/9/20 13:10:15 | 华诺云谱 👁 阅读
ClickHouse v25.8.6.11-lts 发布解析:路径包含判断、Mutation Patch 与 EmbeddedRocksDB 等五处修复的源码级解读
ClickHouse v25.8.6.11-lts 发布解析:路径包含判断、Mutation Patch 与 EmbeddedRocksDB 等五处修复的源码级解读【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse本篇基于官方 changelog v25.8.6.11-lts 展开,逐条解析该 LTS 版本相对 v25.8.5.17-lts 引入的 4 个 Bug Fix 与 1 个内部调整,并结合当前仓库中的源码实现(src/Common/filesystemHelpers.cpp、src/Storages/RocksDB/StorageEmbeddedRocksDB.cpp 等)与测试用例说明每项修复的实际作用与影响面。读完本文,你可以判断该版本是否需要纳入生产 LTS 升级路径,并能从源码层面理解每处修复为什么重要。版本坐标:这个 release 与什么做对比changelog 条目明确给出对比基线:ClickHouse release v25.8.6.11-lts (f1c4c24eb5a) as compared to v25.8.5.17-lts (319dadd8b34)即本版本以 commitf1c4c24eb5a构建,差异范围是相对于上一个 LTS 版本 v25.8.5.17-lts(commit319dadd8b34,见 v25.8.5.17-lts 的 changelog)。本次发布包含 5 条变更记录:分类条目说明主要贡献者Bug FixMakepathStartsWithonly match paths under the prefix修正路径前缀包含判断的语义Raúl MarínBug FixFixed applying patches to columns with default expression that are missing in data parts修复对数据分片中缺失的带默认表达式列应用 patch 的问题Anton PopovBug FixFix EmbeddedRocksDB upgrade修复嵌入式 RocksDB 表升级问题Raúl MarínBug FixIgnore only not found errors fors3_plain_rewritable缩小s3_plain_rewritable磁盘元数据加载时的错误忽略范围Azat KhuzhinNOT FOR CHANGELOG / INSIGNIFICANTEmbeddedRocksDB: Go back to usingdata/path by default内部调整:默认数据路径改回data/子目录Raúl Marín值得注意的 changelog 惯例:所有条目都以 Backported in #xxxxx 开头,表示该修复先落在主分支,再通过后向移植(backport)PR 进入 25.8 LTS 分支。对于跟踪 LTS 分支的团队,这意味着这些修复的完整上下文讨论发生在 backport 关联的原始 issue/PR 上,而 changelog 只保留结论性摘要。修复一:pathStartsWith只匹配真正位于前缀之下的路径问题背景pathStartsWith(path, prefix)是 ClickHouse 内部用于路径包含关系校验的基础工具函数,大量用于磁盘边界检查、对象存储前缀校验等场景。如果它退化为简单的字符串前缀比较,就会出现典型的经典误判:/data/other-tenant会被认为以/data开头。修复目标正是让语义严格限定为路径必须位于前缀目录之下。当前实现在 src/Common/filesystemHelpers.cpp 中,pathStartsWith的核心逻辑是:bool pathStartsWith(const std::filesystem::path path, const std::filesystem::path prefix_path) { if (containsEmbeddedNul(path) || containsEmbeddedNul(prefix_path)) return false; auto rel fs::relative(path, prefix_path); if (rel.empty() || rel ..) return false; while (rel.has_relative_path()) { rel rel.parent_path(); if (rel ..) return false; } return true; }实现思路是:先计算path相对prefix_path的相对路径,然后逐层向上遍历相对路径中的每一级;只要任意一级出现..(即意味着要逃出前缀目录),立即返回false。只有整个相对路径完全处于前缀之下,才返回true。这与字符串前缀比较有本质区别:比较的是目录层级包含关系,而不是字符序列前缀。同一个文件中还有一个变体fileOrSymlinkPathStartsWith(src/Common/filesystemHelpers.cpp),差异在于先对path做fs::absolute(...).lexically_normal()归一化,再执行同样的..遍历检查——其注释说明这样做是为了不解析符号链接本身(Path is not canonized because otherwise path will not be a path of a symlink itself),同时保证包含判断的正确性。安全硬化的配套测试仓库中的 src/Common/tests/gtest_path_starts_with_embedded_nul.cpp 专门针对该函数族建立了边界测试。从测试注释可以看出设计意图:包含检查比较的是完整字符串,而后续所有 syscall(open、mkdir、stat)都会在第一个 NUL 处截断;形如target\0/回穿到前缀的路径的畸形路径若不做拦截,就会被误判为位于前缀内而实际指向别处。测试用例PathStartsWithEmbeddedNul验证了:正向对照:不含 NUL 的同一回穿路径会被判为包含(证明翻转结果的是 NUL);注入 NUL 后的逃逸路径返回false;路径或前缀中任意位置出现 NUL 均被拒绝(fail-closed)。影响面从源码结构看,pathStartsWith/fileOrSymlinkPathStartsWith被广泛调用,涉及 src/Databases/DatabaseFilesystem.cpp、src/Storages/ObjectStorage/Utils.cpp、src/Disks/DiskFromAST.cpp、src/Formats/FormatSchemaInfo.cpp 等模块。这意味着该修复不仅是一个工具函数修正,而是提升了整个路径必须落在指定磁盘/目录/user_files 之内这类边界校验的可信度——凡是基于字符串前缀误匹配绕出边界的场景,都会在这一层被拦下。修复二:对数据分片缺失的带默认表达式列应用 patch问题背景changelog 摘要:Fixed applying patches to columns with default expression that are missing in data parts.在 MergeTree 家族中,patch指 ALTER 语句产生的修改(如ALTER TABLE ... UPDATE、MODIFY COLUMN ... DEFAULT等)写入的额外列数据(Mutation 产生的.binpatch 文件与 extra 信息)。一个典型的生产场景是:表结构演进后,老分片(part)中物理上不存在某个带默认表达式的列(该列从未物化、或已被 TTL 过期清理),此时仍需要对 patch 做正确的求值与合并。修复前这一组合会出问题。源码中的相关处理脉络从源码结构看,这一区域的处理复杂度在 src/Storages/MergeTree/MergeTask.cpp 的注释中有直接体现:/// Handling missing columns that have default expressions is non-trivial and currently unresolved /// ... /// 1. A default expression may depend on other columns, which themselves may be missing or expired,以及紧随其后的判断:Any storage column not present in any part and without a default expression is considered expired。这说明列缺失但有默认表达式与列缺失且无默认表达式(视为已过期)是两条不同分支:前者需要触发默认表达式求值(evaluateMissingDefaults相关路径,参见 src/Storages/MergeTree/IMergeTreeReader.h 中关于required by evaluateMissingDefaults so that it can resolve default expressions for virtual columns 的说明),后者直接视为过期列跳过。本次修复保证 patch 应用阶段也遵循了同样的区分逻辑,而不是把缺失列一律当作不可用或一律按缺失处理。对使用者的意义如果你的集群在 25.8 LTS 上做过表结构演进(新增带DEFAULT表达式的列) 对历史分区发起过 Mutation,升级到此版本可以消除 patch 应用失败或结果不一致的隐患。升级后无需额外配置,属于纯行为修正。修复三与内部调整:EmbeddedRocksDB 升级修复,默认数据路径回到data/本次发布中两条条目同属 EmbeddedRocksDB(ENGINE EmbeddedRocksDB,ClickHouse 内置的 RocksDB 存储引擎,实现位于 src/Storages/RocksDB/ 目录):Bug Fix:Fix EmbeddedRocksDB upgrade(修复嵌入式 RocksDB 表的升级);NOT FOR CHANGELOG / INSIGNIFICANT:Go back to usingdata/path by default(改回默认使用data/路径)。第二条被标记为insignificant / 不进 changelog,但从 changelog 条目可以推断它与第一条是配套动作:升级路径相关的修复与默认数据目录的默认值回退同时落地。默认路径的源码依据在 src/Storages/RocksDB/StorageEmbeddedRocksDB.cpp 中可以看到当前的路径决策逻辑:if (rocksdb_dir.empty()) { /// We create tables under the database directory by default /// and enforce user_files path check for explicitly declared paths rocksdb_dir context_-getPath() relative_data_path_; } else { ... if (!is_local !fileOrSymlinkPathStartsWith(fs::path(rocksdb_dir), user_files_path)) throw Exception(ErrorCodes::BAD_ARGUMENTS, Path must be inside user-files path: {}, user_files_path.string()); }两个要点:未显式指定rocksdb_dir时,数据目录取上下文路径 相对数据路径,即落在数据库目录下的默认子路径(对应data/布局)。这与Go back to usingdata/path by default 的条目相互印证——默认布局回到了与常规 MergeTree 表一致的数据库目录结构,降低了从旧版本升级时的路径不匹配风险。显式指定rocksdb_dir时,server 模式下该路径必须位于user_files_path之内,而校验手段正是fileOrSymlinkPathStartsWith——即上一篇小节的修复一。这两处修复因此形成协同:边界判断函数变严格后,EmbeddedRocksDB 的显式路径校验也随之更可靠。另外,rocksdb_dir在打开时会做存在性校验,打开失败会抛出ROCKSDB_ERROR(Failed to open rocksdb path at: ...,见同文件 L1075 附近),因此升级后若遇到旧目录布局不兼容,错误信息会直接指向具体路径,便于排查。升级建议对使用EmbeddedRocksDB表的 25.8 LTS 部署,建议:升级到本版本以获取 upgrade 修复;若曾依赖显式rocksdb_dir指向user_files之外的路径,先核对配置——修复后的边界校验会拒绝此类路径;若之前处于默认路径被改动过的中间版本,回到默认的data/布局后,请确认数据目录位置与旧版本一致,避免数据看不见。修复四:s3_plain_rewritable只忽略 not found 错误背景:plain_rewritable元数据机制是什么*_plain_rewritable是 ClickHouse 的一类对象存储磁盘类型,在 src/Disks/DiskObjectStorage/ObjectStorages/ObjectStorageFactory.cpp 中注册了s3_plain_rewritable、azure_plain_rewritable、local_plain_rewritable三种对象存储;磁盘类型s3_plain_rewritable的注册与文档描述见 src/Disks/DiskObjectStorage/RegisterDiskObjectStorage.cpp(语法:disk(type s3_plain_rewritable, endpoint ...));对应的元数据实现为plain_rewritable类型,在 src/Disks/DiskObjectStorage/MetadataStorages/MetadataStorageFactory.cpp 注册,核心加载逻辑位于 src/Disks/DiskObjectStorage/MetadataStorages/PlainRewritable/MetadataStorageFromPlainRewritableObjectStorage.cpp。该机制的工作方式是:在对象存储中用可被直接重写的普通对象模拟目录树(根级文件存放在__root/前缀下,目录元数据存放在专用 metadata 前缀下),加载时通过iterate遍历这些对象并在多线程池(PLAIN_REWRITABLE_META_LOAD线程名)中并发读取各目录元数据文件。修复点:错误忽略范围收窄changelog 原文:Ignore only not found errors fors3_plain_rewritable(which may lead to all sort of troubles).即:在元数据加载/刷新过程中,此前会把范围更宽的错误都静默忽略掉;修复后只忽略对象不存在(not found)这一类预期内错误,其余错误(例如权限、网络、服务端 5xx 等)不再被吞掉,而是如实向上抛出。括号中的 may lead to all sort of troubles 是作者对过宽忽略后果的直接警示——元数据在部分失败下被当作成功加载的残缺视图,后续读写行为会难以排查。从加载流程源码看(MetadataStorageFromPlainRewritableObjectStorage.cpp),每个目录元数据对象在独立任务中读取,读取前后涉及readObject与 etag 对比等步骤;把忽略哪些异常的判定收紧为仅 not-found,正是对这条并发加载链路的健壮性修正。影响面使用该磁盘类型的典型形态是把 S3(或 Azure/本地)作为可重写目录型存储(例如配合metadata_type plain_rewritable的磁盘配置,参考 src/Disks/tests/gtest_disk_object_storage.cpp 中的local_plain_rewritable_disk测试配置)。对这类部署,升级到本版本后应留意:此前被静默吞掉的环境问题(凭证、网络)现在会以明确错误形式暴露——这属于预期行为变化,而非新问题。小结:升级决策要点所有使用 25.8 LTS 的部署:本版本 4 个 Bug Fix 全部为行为正确性修复,无新增功能、无配置项变更,属于低风险、高收益的常规 LTS 维护升级。路径边界敏感场景(user_files外路径访问、对象存储前缀校验、自定义磁盘路径):修复一提升了pathStartsWith的语义严谨性,并有专门的 embedded NUL 逃逸测试(src/Common/tests/gtest_path_starts_with_embedded_nul.cpp)背书。使用 MergeTree Mutation 带默认表达式列演进的表:修复二直接针对 patch 应用路径,可消除缺失列场景下的不一致。使用EmbeddedRocksDB的部署:关注数据目录默认布局回到data/的配套调整,升级前核对显式rocksdb_dir是否位于user_files之内。使用s3_plain_rewritable的部署:错误暴露面扩大是修复目标,若升级后出现此前看不见的对象存储报错,应按真实错误处理而非视为回归。本文全部事实依据来自仓库内文档 docs/changelogs/v25.8.6.11-lts.md、前序版本 docs/changelogs/v25.8.5.17-lts.md 及上文列出的源码与测试文件;个别由源码结构推断的表述已显式标注。【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

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

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

你可能需要的服务

订阅华诺云谱资讯周报

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