news 2026/9/19 21:57:20

ClickHouse v26.3.3.20-lts 缺陷修复详解:异步插入计数、备份路径安全与 12 项稳定性补丁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ClickHouse v26.3.3.20-lts 缺陷修复详解:异步插入计数、备份路径安全与 12 项稳定性补丁

ClickHouse v26.3.3.20-lts 缺陷修复详解:异步插入计数、备份路径安全与 12 项稳定性补丁

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

导读

本文基于当前仓库 docs/changelogs/v26.3.3.20-lts.md 展开,逐条解析 ClickHouse v26.3.3.20-lts(commit 5342e88d453)相对 v26.3.2.3-lts(commit a1a0cf365ce)的 20 项变更。本版本属于 LTS 分支的缺陷修复(Bug Fix)迭代,重点覆盖异步插入(async insert)统计口径、备份恢复(RESTORE)路径校验安全加固、session_timezone解析一致性、以及字典卸载与文本检索索引等多处崩溃场景。读完本文,你将掌握每个修复的触发场景、修复思路、可复现的 SQL 形态,以及对应源码位置,便于自行验证与回归测试。


一、版本概览与定位

v26.3.3.20-lts 是一个典型的LTS 分支缺陷修复版本:不引入新功能,专注于修复官方稳定版中用户可见的错误行为(user-visible misbehavior)。变更清单可归为三类:

变更分类数量说明
Bug Fix14官方稳定版中用户可见的错误行为修复
NO CL CATEGORY1未归类(缺少 changelog 分类标签)的修复
NOT FOR CHANGELOG / INSIGNIFICANT5内部修复或非显著变更,不面向用户公告

从修复分布看,本版本的高频主题集中在三块:异步插入(async insert)链路(计数、时区解析、结果行数)、备份/恢复(Backup/RESTORE)路径安全、以及服务器运行期崩溃(字典卸载、ULID 解析、文本检索索引等)。


二、异步插入(Async Insert)链路的三项修复

异步插入是 ClickHouse 为高吞吐小批量写入设计的机制:客户端以async_insert=1提交写入,服务端先将数据缓冲,再合并为较大批次落盘。本版本针对该链路修复了三处一致性问题。

2.1 修复 query_log 与客户端输出中的零统计

变更:修复异步插入在query_log与客户端输出中上报written_rowsread_rowsresult_rows全为 0 的问题(PR #99879)。

影响面:所有使用async_insert=1的写入用户。此前查询日志中的行数统计失真,会干扰基于query_log的监控、审计与计费统计。

源码印证:异步插入的启用与回退逻辑集中在 src/Interpreters/executeQuery.cpp 的executeQuery路径中,涉及async_insertwait_for_async_insertwait_for_async_insert_timeout三个设置的读取,以及数据量过大时同步执行的降级判断(LOG_DEBUG(logger, "Setting async_insert=1, but INSERT query will be executed synchronously..."))。本次修复正是补全该链路上行数统计的传递。

2.2 修复 HTTP 与 TCP 异步插入忽略 session_timezone

变更:修复session_timezone在异步插入(TCP 协议)以及所有 HTTP 协议插入场景中被忽略、导致DateTime值解析错误的问题(PR #100647)。

影响面:依赖session_timezone会话设置解析字符串时间戳的用户。此前同一 SQL 在同步 TCP 插入与异步/HTTP 插入下可能得到不同的时间存储值,属于典型的一致性问题。

修复思路:确保解析DateTime时统一携带会话时区上下文,而非退化为默认时区。

2.3 修复结果行数重复计数

变更:修复结果行数(result rows)被重复计算的问题(PR #101226),与 2.1 同属统计口径修复,均由异步插入路径的计数逻辑引起。


三、备份恢复(RESTORE)路径校验安全加固

变更:在恢复过程中校验备份元数据中的文件条目路径,拒绝路径穿越(path traversal)、绝对路径与空名称(PR #100483)。

风险场景:备份文件可能被篡改或损坏(corrupted/tampered backup)。若元数据中的文件路径未经校验直接用于写盘,恶意或损坏的备份可在恢复时把文件写到预期目录之外,构成写任意路径的漏洞。该问题由 Pablo Marcos 报告并修复。

源码印证:校验函数validateFileNameFromBackup实现在 src/Backups/BackupImpl.cpp,校验规则完整覆盖文档所述三类攻击面:

  1. 绝对路径/根路径path.is_absolute() || path.has_root_name() || path.has_root_directory()任一成立即抛INSECURE_PATH
  2. 路径穿越:经path.lexically_normal()归一化后,若首段为..(即解析后逃出备份根目录)则拒绝;
  3. 空名称/退化路径:归一化后为空或.时抛BACKUP_DAMAGED
  4. 附加校验:要求路径本身已是归一化形式(normalized.string() == file_name),避免a//b这类非归一化写法绕过前缀裁剪逻辑。

该校验分别应用于备份条目主文件(info.file_name)与数据文件(info.data_file_name),覆盖了 src/Backups/BackupImpl.cpp 与 src/Backups/BackupImpl.cpp 两处入口。


四、服务器运行期崩溃与逻辑错误修复

4.1 字典加载与服务器关闭的并发竞态

变更:修复关闭服务器时加载字典触发的空指针解引用(segfault)。根因是字典线程并发调用Context::getUserDefinedSQLObjectsStorage(解引用user_defined_sql_objects_storage),而主线程的Context::shutdown会将该字段置空(PR #100839)。

修复思路:在Context::shutdown之前,先禁用字典加载器的后续更新、终止正在运行的字典查询并 join 字典加载线程——即与普通查询的关闭流程对齐,保证共享上下文在卸载前不再被并发访问。

4.2 ULIDStringToDateTime 对非 ASCII 输入的缓冲区溢出

变更:修复ULIDStringToDateTime在输入包含非 ASCII 字节时的缓冲区溢出(PR #100843)。

源码印证:该函数位于 src/Functions/ULIDStringToDateTime.cpp,接受StringFixedString(26)输入并返回毫秒精度的DateTime64(3)。其解码函数decode现在先在 src/Functions/ULIDStringToDateTime.cpp 中对 26 字节逐一校验:

校验所有字节均为 ASCII 后再调用ulid_decode,因为ulid_decode以字符值作为数组下标——带符号 char 值 ≥ 128 会产生负下标,导致越界读取。

任何非 ASCII 字符(data[i] >= 128)都会抛出BAD_ARGUMENTS,例如:

SELECT ULIDStringToDateTime('01GNB2S2FGN2P93QPXDNB4EN2R'); -- 正常解析 -- 非法字符输入将得到:Cannot parse ULID: non-ASCII character at position N

该函数自 v23.3 引入(IntroducedIn = {23, 3}),建议升级后对包含脏数据、编码混用的 ULID 列做回归验证。

4.3 文本检索索引与元组子查询 IN 的崩溃

变更:修复使用文本检索索引(text search index)时,IN子句包含元组子查询导致的崩溃,例如WHERE (id, str) IN (SELECT (id, str) FROM ...),以及子查询列数与左侧元组不匹配的场景(PR #100959)。

影响面:对带全文/文本索引的表执行复合键IN (SELECT ...)查询的用户。

4.4 has() + PREWHERE/WHERE 与 LowCardinality 元组键崩溃

变更:修复has()函数配合 PREWHERE/WHERE、作用于包含 LowCardinality 元素的元组键时导致的服务器崩溃(PR #100760)。

4.5 intDiv / intDivOrZero 与 Nullable 元组数组异常

变更:修复intDiv/intDivOrZero作用于可空元组数组时的异常,文档给出复现形态:

SELECT intDiv([divide((1, 2), ... AND NULL)], 2)

(PR #100895)建议在升级后用含NULL的嵌套元组数组数据对该类函数做回归测试。

4.6 缓存盘"Having zero bytes"逻辑错误

变更:修复缓存相关逻辑错误Having zero bytes, ...。根因是远端对象在listread之间被覆盖,导致读取到过期对象元数据(PR #101219),典型发生于共享存储 + 本地缓存盘场景。另有一项同主题修复(PR #101230)随本版本合入。


五、聚合与优化器相关的兼容性修复

5.1 sumCountOrDefault 旧序列化状态读取失败

变更:修复sumCountOrDefault聚合函数在含一个及以上Nullable参数时,因Nullable(Tuple)类型的引入而无法读取旧版本序列化状态的问题(PR #101021,关闭 issue #100882)。

影响面:升级前写入的、使用sumCountOrDefault的物化视图或AggregatingMergeTree分区数据。不修复会出现跨版本状态反序列化失败。

源码印证:该函数注册于 src/AggregateFunctions/registerAggregateFunctions.cpp,实现位于 src/AggregateFunctions/AggregateFunctionSumCount.cpp。升级 LTS 后建议对存量聚合状态做一次读取冒烟测试。

5.2 StorageAlias 引擎参数求值时机

变更StorageAlias的引擎参数在保存表定义前先求值,使currentDatabase()这类表达式在写入数据库前被解析为字面量(PR #100902)。此前若在非默认库中重建依赖该别名表的对象,可能得到错误解析结果。

5.3 optimizeLazyMaterialization 与投影 PREWHERE 异常

变更:修复optimizeLazyMaterialization在使用含 PREWHERE 的投影(projection)且带ORDER BY ... LIMIT时抛异常的问题(PR #101115),属于查询优化器在投影 + 惰性物化组合路径下的边界修复。


六、NO CL CATEGORY 与内部修复

6.1 NO CL CATEGORY

  • PR #101241(Anton Popov):一项未附 changelog 分类标签的修复,随本版本合入。

6.2 NOT FOR CHANGELOG / INSIGNIFICANT(内部修复)

该分类用于不面向用户公告、但对系统健壮性有实际意义的内部变更:

变更内容说明
PR #99741修复缓存盘(cache disk)启动逻辑此前启动时跳过了访问检查(access check),存在权限语义偏差
PR #100064修复 issue #99996内部行为修正
PR #100522removeObjectsIfExist由顺序删除改为批量删除涉及对象存储清理路径的 I/O 优化
PR #100907配置重载后正确重新计算位置(locations)修复热更新配置后缓存位置未同步的问题
PR #101226修复结果行数重复计数与 2.3 同一修复,此分类下重复列出

七、升级与验证建议

  1. 统计口径回归:异步插入用户应检查query_logwritten_rows/read_rows/result_rows是否恢复正常,可通过system.query_log对比同步与异步插入的统计差异。
  2. 备份安全:建议在升级后执行一次包含相对路径、嵌套目录的BACKUP/RESTORE往返测试,确认 src/Backups/BackupImpl.cpp 中的路径校验不影响正常备份;同时可利用validateFileNameFromBackup的报错信息(INSECURE_PATH/BACKUP_DAMAGED)识别异常备份。
  3. 时区一致性:设置session_timezone后分别通过 HTTP 与 TCP、同步与异步方式插入同一DateTime字符串,比对存储结果是否一致。
  4. 崩溃类回归:覆盖has()+ LowCardinality 元组键 PREWHERE、文本检索索引 + 元组子查询INULIDStringToDateTime非 ASCII 输入、intDiv+ Nullable 元组数组四类场景,确认不再抛异常或崩溃。
  5. 聚合状态兼容:对存量sumCountOrDefault(Nullable)状态执行读取验证,确认新版本可正常反序列化旧状态。

结语

v26.3.3.20-lts 虽是一个纯修复版本,但其价值集中在三类高风险面上:异步插入的统计与时区一致性、RESTORE 的路径安全边界,以及多个并发/越界崩溃点。对生产环境而言,上述第 3.2(备份路径校验)与 4.2(ULID 溢出)两项具备安全属性,建议优先评估升级;统计口径类修复则适合作为监控告警基线校正的依据。所有修复均可对照本文给出的源码路径,在 docs/changelogs/v26.3.3.20-lts.md 的原始条目中找到对应 PR 号,进行二次核验。

【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 21:53:56

Docker跨平台部署原理:Windows与Linux底层差异解析

1. 为什么 Docker 部署总在“最后一步”卡住?——从 Windows 和 Linux 的底层差异说起 你有没有遇到过这样的场景:照着网上教程,一行行敲完 docker --version 、 docker run hello-world ,Windows 上弹出“Virtualization su…

作者头像 李华
网站建设 2026/9/19 21:52:46

彩灯控制器设计:NE555+CD4040+74LS138数字电路闭环实现

简介:本资源是一份面向电子信息类本科生的数字电子技术课程设计报告,聚焦彩灯控制器硬件系统实现,帮助学习者掌握NE555定时器、74LS138译码器与CD4040计数器的协同应用原理与工程实践方法。报告完整覆盖设计目的、总体方案、功能模块分析&…

作者头像 李华
网站建设 2026/9/19 21:52:28

Unity WebGL透明背景全攻略:画布透明配置与.jslib排查指南

做数字孪生大屏那阵子,我被Unity WebGL默认的“实心矩形”怼得头皮发麻。模型渲染得挺漂亮,结果一嵌进网页,一个四四方方的背景块直接切断整个页面的视觉流。后来花了两三天时间把画布透明这件事彻底捋清楚,才发现Unity WebGL的透…

作者头像 李华