
ClickHouse v21.12.3.32-stable 维护版深度解析9 项关键 Bug 修复的源码级解读【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse本文基于 ClickHouse 官方仓库 docs/changelogs/archive/v21.12.3.32-stable.md 中记录的 v21.12.3.32-stable 发布说明展开逐条解析该维护版本包含的 9 项 Bug 修复与 4 项内部改进并结合仓库源码说明每项修复背后的机制、影响范围与验证方式。读完本文你将理解 ClickHouse stable 维护版的发布节奏与 Backport 流程掌握这些修复涉及的核心模块Keeper、MergeTree、物化视图、MySQL 引擎、字符串正则函数、HDFS、HTTP 服务的工作原理并知道如何在自己的集群上规避相关风险、验证修复效果。版本背景stable 维护版与 Backport 机制v21.12.3.32-stable 是 ClickHouse 21.12 稳定分支上的一个补丁维护版本其对照基线为 v21.12.2.17-stable。这类小版本发布遵循 ClickHouse 的语义化版本惯例主版本 21.12 代表 2021 年 12 月的主功能发布后续的.3.32是维护号仅包含缺陷修复不引入新功能目的是在不改变 SQL 语义的前提下快速修复线上问题。从 changelog 的分类可以看出 ClickHouse 维护版的修复分级体系Bug Fix常规缺陷修复本版本 1 项通常修复不影响官方稳定版发布标准的边缘问题Bug Fix (user-visible misbehaviour in official stable release)官方稳定版中用户可见的行为异常本版本 8 项是维护版中最需要关注的部分NOT FOR CHANGELOG / INSIGNIFICANT内部改进与代码合并不直接对用户暴露行为变化本版本 4 项。每条修复条目均标注了 Backported in 字样对应 ClickHouse 的 Backport 机制修复首先合入主分支master随后由维护者通过机器人将相关 commit 拣选cherry-pick回稳定分支并重新构建发布。这也是为什么维护版补丁说明中总能同时看到上游 PR 号与回移 issue 号。升级到该版本的用户实质上是将 21.12 分支积累的一批已修复缺陷一次性纳入。Keeper响应发送后及时移除操作BackportedClickHouse Keeper handler should remove operation when response sentPR #32988。该修复涉及 ClickHouse Keeper21.12 起从 ZooKeeper 迁移出的内置协调服务的请求处理路径。Keeper 的请求处理核心位于 src/Coordination/KeeperRequestDispatcher.cpp当前仓库中该模块已演进为KeeperRequestDispatcher/KeeperRequestDispatcherOld等实现其职责是将客户端请求如create、set、delete、exists分发给底层状态机KeeperStateMachine执行并负责维护请求队列、session 管理与请求完成回调。该 Bug 的表现是当响应已经发送给客户端后对应的操作项未被从处理器的跟踪结构中移除导致内部状态与真实连接状态不一致。在长时间运行、请求量大的 Keeper 实例上这会造成操作记录堆积、内存占用缓慢增长并可能干扰后续请求的完成判定。修复方式是在响应发送完成回调触发后同步清理该操作记录保证操作生命周期与连接生命周期一致。该修复对使用 ClickHouse Keeper 替代 ZooKeeper 的复制表、分布式协调场景尤为重要建议部署了 Keeper 的集群优先升级。物化视图目标为 JOIN 或 SET 表时的 LOGICAL_ERRORBackportedFix LOGICAL_ERROR when the target of a materialized view is a JOIN or a SET tablePR #32669。MATERIALIZED VIEW在 ClickHouse 中是一种在数据写入源表时自动执行查询并写入目标表的特殊表结构。JOIN 表StorageJoin与 SET 表StorageSet是两类内存态表引擎它们的数据无法被常规的 SELECT 全量扫描直接读取——JOIN 表只能作为JOIN的右表使用SET 表只能配合IN子句使用。此前若将物化视图的目标指定为这类表查询规划阶段会触发LOGICAL_ERROR异常——这是 ClickHouse 内部一致性检查的报错形式表示本不该出现的状态被触达用户无法通过配置规避。修复后物化视图写入 JOIN/SET 表的行为被正确处理或给出明确的语义化报错不再产生内部断言级别的失败。如果生产环境中存在这类错误配置的物化视图升级后可避免日志中出现LOGICAL_ERROR刷屏。MySQL 引擎数据库连接失败不再阻断服务启动BackportedServer might fail to start if database with MySQL engine cannot connect to MySQL serverPR #32802修复 issue #14441。这是运维影响最大的一项修复。使用ENGINE MySQL(...)创建数据库后ClickHouse 服务启动时或首次加载该数据库元数据时需要与远程 MySQL 建立连接以枚举表结构。旧版本中若远端 MySQL 暂时不可达网络抖动、MySQL 重启、防火墙变更服务启动流程会被连接异常直接打断导致 ClickHouse 整体起不来——一个远程辅助源的故障却拖垮了整个本地数据库服务。当前仓库源码 src/Databases/MySQL/DatabaseMySQL.cpp 中的mysqlToleratedConnectionFailureLogLevel()函数清晰地体现了这一分类思想函数在 catch 块中重新抛出当前异常以分类——mysqlxx::ConnectionFailed、mysqlxx::ConnectionLost、Poco::Net::NetException以及ALL_CONNECTION_TRIES_FAILED均被降级为LogsLevel::warning仅记录警告不阻断流程而其他异常类型逻辑错误、磁盘错误等保持LogsLevel::error级别保证真正的问题不被掩盖。修复后MySQL 数据库连接失败被容错处理服务可以正常启动远程库以不可达状态呈现待网络恢复后自动重建连接。MergeTree并发 mutation 过多时的静默跳过修复BackportedMergeTree table engine might silently skip some mutations if there are too many running mutations or in case of high memory consumptionPR #32814修复 issue #17882。MUTATION 是 ClickHouse 对 MergeTree 系列表的异步数据变更机制ALTER TABLE ... UPDATE、DELETE、MATERIALIZE等执行由后台任务驱动。旧实现中当同时运行的 mutation 数量过多或内存压力较大时部分 mutation 可能被静默跳过——即任务调度环节认为该 mutation 不需要处理但实际并未完成数据变更用户查询到的仍是旧数据且system.mutations中的状态长期不收敛。该 Bug 的根因在于 mutation 处理的判定条件在资源受限场景下产生误判。修复确保 mutation 任务在资源受限时进入等待/重试而非被跳过保证ALTER ... UPDATE/DELETE语义的最终一致性。对于大量使用轻量数据更新尤其是DELETE WHERE清理历史分区的场景的集群此项修复直接关系到数据正确性建议核对升级后的system.mutations状态是否全部收敛为 done。远程文件系统异步读 lazy seek 优化修复BackportedFix optimization with lazy seek for async reads from remote fsPR #32835关闭 issue #32803。ClickHouse 支持将数据存储在 S3、HDFS 等远程文件系统上并为此实现了异步预取读取路径local_filesystem_read_prefetch/remote_filesystem_read_prefetch等设置控制的 ReadBuffer 异步化。lazy seek 优化是指延迟执行 seek 操作、与后续读取合并以减少远程请求次数的优化手段。该修复针对异步读路径下 lazy seek 与预取缓冲状态不同步的问题——在某些列读取场景中seek 被延迟执行后预取缓冲区的位置信息失效导致读取结果错位或错误。修复后远程文件系统异步读取的 seek 语义与缓冲状态保持一致。对于将 MergeTree 数据存储在 S3 的冷热分层集群此项修复可避免在特定查询模式如随机访问部分列、ORDER BY涉及预取下出现数据读错的问题。replaceRegexpAll空匹配子串的回归修复BackportedFix a regression in replaceRegexpAll function. The function worked incorrectly when matched substring was emptyPR #32945关闭 issue #32777 与 #30245。这是最便于可复现验证的一项修复。replaceRegexpAll(haystack, pattern, replacement)用于将字符串中所有匹配正则的子串替换为指定内容是数据清洗中的高频函数。其实现位于 src/Functions/replaceRegexpAll.cpp通过FunctionStringReplaceReplaceRegexpImplNameReplaceRegexpAll, ReplaceRegexpTraits::All, ...注册并提供了REGEXP_REPLACE别名大小写不敏感。Bug 表现为当匹配到的子串为空例如 pattern 为^、$、|这类可匹配零长度位置的表达式时替换结果错误。核心处理逻辑在 src/Functions/ReplaceRegexpImpl.h 的processString循环中while (match_pos haystack_length) { ... if (searcher.Match(haystack, match_pos, haystack_length, re2::RE2::Anchor::UNANCHORED, matches, num_captures)) { ... if (match.empty()) { /// Step one character to avoid infinite loop match_pos; if (match_pos haystack_length) can_finish_current_string true; } } }replaceRegexpAll的文档明确记载了这一边界行为As an exception, if a regular expression worked on an empty substring, the replacement is not made more than once.作为特例若正则匹配到空子串替换不会重复执行一次以上。该头文件中的注释也指出不同语言/数据库对全局替换遇到空匹配的行为定义并不一致Perl、PHP、Python 会输出HelloHelloHello而 Node.js、Ruby、sed、PostgreSQL 各有不同结果。ClickHouse 采用空匹配只替换一次的约定而本次修复正是让该约定在空匹配场景下真正生效当前源码中match_pos的前进策略配合can_finish_current_string的终止判定保证了循环不陷入死循环且输出正确。使用该函数处理^、$、\b等零宽度匹配模式的用户升级后可观察到结果与文档约定一致同时可参考 replaceRegexpAll.cpp 中的官方示例验证行为SELECT replaceRegexpAll(Hello, World!, ^, here: ) AS res; -- ┌─res─────────────────┐ -- │ here: Hello, World! │ -- └─────────────────────┘HDFSHA namenode 地址 URL 检查修复BackportedFix hdfs url check that didnt allow using HA namenode addressPR #32976回归由上游 PR #31042 引入。HDFS 表引擎与hdfs()表函数通过 URL 指定远端路径。该修复针对 URL 校验逻辑的回归修复前的校验不允许 HAHigh Availabilitynamenode 的地址形式。HDFS HA 部署使用逻辑名称logical nameservice ID而非单个主机名例如hdfs://nameservice1/path其解析依赖hdfs-site.xml中的dfs.nameservices配置。旧校验逻辑误将这类合法地址判为非法导致 HA 模式下 HDFS 表无法使用。修复后URL 检查正确放行 HA 地址。对于使用hdfs://nameservice/...形式路径、依赖 HDFS 高可用配置的集群升级是使能该功能的前提。HTTP 接口cancel_http_readonly_queries_on_client_close 上下文泄漏修复BackportedFix Context leak in case of cancel_http_readonly_queries_on_client_closePR #32982。cancel_http_readonly_queries_on_client_close是 ClickHouse HTTP 服务的重要保护设置当只读 HTTP 查询的客户端断开连接时服务端自动取消该查询避免后台继续空转浪费资源。该设置的原生逻辑在 src/Server/HTTPHandler.cpp 中体现if (!settings[Setting::run_query_in_background] settings[Setting::readonly] 0 settings[Setting::cancel_http_readonly_queries_on_client_close]) { append_callback(context, request { /// Assume that at the point this method is called no one is reading data from the socket any more: /// should be true for read-only queries. if (!request.checkPeerConnected()) context-killCurrentQuery(); }); }即仅在readonly 0只读模式且未后台执行时通过进度回调检测对端连接状态断开则调用killCurrentQuery()取消查询。本次修复的内容是取消查询时Context未被正确释放导致已上传到服务端的外部表数据external dataHTTP 接口通过 multipart/form-data 上传的临时表及其他资源发生泄漏长期运行会造成内存持续增长。修复后查询被取消的同时相关Context及外部表资源得到完整回收。对外提供 HTTP API、且开启了该保护设置的服务端升级可消除资源泄漏隐患。LowCardinality预读开启时的版本校验错误修复BackportedFix errorInvalid version for SerializationLowCardinality key columnin case of reading from LowCardinality column with local_filesystem_read_prefetch or remote_filesystem_read_prefetch enabledPR #33046。LowCardinality是 ClickHouse 的字典编码类型将重复度高的字符串压缩存储其序列化分为 key字典与 index位置两部分。当local_filesystem_read_prefetch或remote_filesystem_read_prefetch开启时读路径进入预取模式此前的实现会在读取SerializationLowCardinality的 key 列时抛出Invalid version错误使查询直接失败。修复后预取读取与 LowCardinality 字典序列化的版本解析逻辑正确协同。对于在 MergeTree 中大量使用LowCardinality(String)维度列、且依赖本地盘或 S3 预取加速的查询负载此项修复直接消除了一个可稳定复现的查询报错。相关序列化实现可参见 src/DataTypes 目录下的 LowCardinality 相关序列化代码。内部改进NOT FOR CHANGELOG / INSIGNIFICANT该部分 4 项改动不直接改变用户可见行为但体现了 21.12 分支在稳定性上的打磨Improve quotas end-of-interval calculationsPR #32575优化配额quota在时间区间结束时刻的计算逻辑避免区间边界处的配额统计误差影响使用QUOTA做资源管控的用户Fix race in skipping index of type hypothesisPR #32756修复跳过索引hypothesis类型在使用时的竞态条件属数据跳过索引模块的并发安全改进Always apply const-condition-if optimizationPR #32858使const condition的if优化在所有场景下恒常生效属查询优化器的常量折叠改进另外 3 项为维护者对上游分支的合并操作Merge PR #33024、#33022、#33050 至 PR #33061、#33062、#33065属常规同步。升级与验证建议结合本版本的修复清单可按以下步骤规划升级确认版本与渠道当前仓库的 changelog 归档位于 docs/changelogs/archive可对比相邻维护版的修复差异生产环境建议通过官方 apt/yum 仓库或clickhouse-client --version确认当前版本后再执行升级。重点验证项运行SELECT replaceRegexpAll(Hello, World!, ^, here: )确认空匹配替换行为符合文档约定空匹配只替换一次对使用 MySQL 引擎数据库的实例重启 ClickHouse 验证远端 MySQL 不可达时服务仍能启动查看日志中该连接的降级 warning 记录对开启预读local_filesystem_read_prefetch/remote_filesystem_read_prefetch且含LowCardinality列的查询执行回归测试对使用 HDFS HA 地址的hdfs()表执行一次读取验证。观察运行状态升级后关注system.mutations是否全部收敛、Keeper 实例的内存是否平稳、HTTP 服务长时运行内存是否回稳——这三者分别对应本版本三项关键修复的效果。总体而言v21.12.3.32-stable 是一个典型的稳定分支收敛型维护版修复集中在数据正确性mutation、物化视图、replaceRegexpAll、可用性MySQL 引擎启动、HDFS HA与资源管理Context 泄漏、Keeper 操作清理三个维度。对于仍运行在 21.12 分支的集群该版本值得优先升级。【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考