news 2026/9/18 22:13:09

ClickHouse v25.8.20.4-lts 补丁版本解析:递归 CTE 崩溃、Patch Parts 列序与 O_DIRECT 读缓冲 seek 三大修复

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ClickHouse v25.8.20.4-lts 补丁版本解析:递归 CTE 崩溃、Patch Parts 列序与 O_DIRECT 读缓冲 seek 三大修复

ClickHouse v25.8.20.4-lts 补丁版本解析:递归 CTE 崩溃、Patch Parts 列序与 O_DIRECT 读缓冲 seek 三大修复

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

本篇技术指南聚焦 ClickHouse 官方 LTS 分支的最新补丁版本v25.8.20.4-lts(提交2e1cd6354ae),逐条拆解该版本相对 v25.8.19.20-lts 引入的三项 Bug Fix:递归 CTE 搭配remote()view()时的段错误(segfault)、MergeTree 增量 Patch Parts 列顺序不一致导致的LOGICAL_ERROR,以及O_DIRECT模式下异步文件读缓冲的错误 seek 定位。读完本文,你将理解每个缺陷的触发场景、根因所在,以及仓库中对应的底层实现与修复落点,从而能够在生产升级时准确评估影响面。

本文内容以仓库中的官方发布记录 docs/changelogs/v25.8.20.4-lts.md 为主体骨架,并结合src/下相关模块源码进行原理层面的印证与扩展。

版本背景与升级建议

v25.8.20.4-lts 属于 ClickHouse 25.8 系列的 LTS(长期支持)维护分支。从发布记录的版本对比行可以看出,它是 v25.8.19.20-lts 的直接后继版本,全部变更均为Bug Fix(用户可见的官方稳定版行为异常修复),未引入新特性或破坏性变更。因此对于运行 25.8 LTS 系列的集群,这是一个低风险、应尽快合入的补丁升级;修复涉及的三个模块分别为:

编号修复内容涉及模块上游跟踪
1递归 CTE +remote()+view()组合查询段错误Analyzer / 查询执行#99081(随 #99441 回溯)
2Patch Parts 列顺序不匹配导致的LOGICAL_ERRORMergeTree 变更转换#99164(随 #99989 回溯)
3O_DIRECT下异步读缓冲 seek 定位错误IO 异步读#99678(随 #99950 回溯,关闭 #99358)

说明:以上编号取自仓库 changelog 中的 PR/Issue 编号,便于在社区中交叉检索;本文不附外部链接,具体上下文请以仓库源码为准。

修复一:递归 CTE 与remote()view()组合时的段错误

触发场景

在 ClickHouse 中,递归 CTE(Recursive Common Table Expression)通过WITH RECURSIVE定义,其执行依赖一个内部临时表来承载迭代过程的中间结果。当递归查询的初始化(非递归)子查询中同时出现remote()表函数与view()表函数时,v25.8.20.4-lts 之前的版本可能触发段错误(segfault)导致服务进程崩溃,属于用户可见的严重稳定性缺陷。

底层实现印证

递归 CTE 的解析与分析阶段实现在 src/Analyzer/RecursiveCTE.cpp:RecursiveCTETable包装了一个由TemporaryTableHolderPtr持有的临时表存储与列定义,供递归子查询在迭代中反复读写。而实际数据读取由查询计划层完成:

  • src/Processors/QueryPlan/ReadFromRecursiveCTEStep.cpp 通过pipeline.init(...)RecursiveCTESource挂入执行管道;
  • 数据源实现在 src/Processors/Sources/RecursiveCTESource.cpp,其中会校验递归子查询的投影列与recursive_cte_table->columns是否同构(columns.size() != recursive_query_projection_columns.size()时抛出异常)。

当递归 CTE 与非递归的remote()/view()子查询组合时,涉及远程表的列类型/名称解析与本地临时表列定义之间的对齐。从源码结构可以推断,段错误的根因在于这类组合路径下列描述(ColumnsDescription)或存储句柄的初始化存在未覆盖分支,导致空指针解引用。修复通过补全该组合下的初始化与校验逻辑,确保列投影在任何组合下都先校验、后访问,从而消除崩溃。

实操验证建议

升级后可用如下形态的查询做回归验证(注意:remote()参数需替换为你实际的集群地址与表):

WITH RECURSIVE r AS ( SELECT number AS n FROM remote('127.0.0.1:9000', system, numbers) LIMIT 1 UNION ALL SELECT n + 1 FROM r WHERE n < 5 ) SELECT * FROM r;

以及在view()包装场景下重复执行,确认不再出现段错误且结果正确。相关查询计划与递归数据源的实现,可继续阅读 src/Analyzer/UnionNode.cpp、src/Analyzer/RecursiveCTE.h 与 src/Processors/Sources/RecursiveCTESource.h。

修复二:Patch Parts 列顺序不匹配导致的 LOGICAL_ERROR

触发场景

Patch Parts 是 MergeTree 引擎为实现轻量级增量修改而引入的数据部件类型:对已存在 part 的少量列进行修改时,系统以“补丁部件”形式记录增量,读取时在内存中将其与原始 part 合并。当某个 part 上同时存在多个待应用的 patch part,且这些 patch part 与常规 part 的列顺序不一致时,旧版本会抛出LOGICAL_ERROR(“It is a bug”级别异常),导致读取失败。

底层实现印证

列序合并与校验逻辑集中在 src/Storages/MergeTree/AlterConversions.cpp 与 src/Storages/MergeTree/AlterConversions.h:

  • AlterConversions构造时同时接收MutationCommandsPatchPartsForReader,并通过addPatchPart(patch)将每个 patch 追加进patch_parts
  • hasPatches()/getAllPatches()暴露 patch 集合状态;
  • 构造器会对“超过一个 on-fly ALTER MODIFY”的组合抛出不支持异常(见AlterConversions.cppnumber_of_alter_mutations > 1的检查分支),说明该模块对多变更叠加的一致性极其敏感。

修复前,patch part 合并时直接以 patch 自身列顺序为准进行拼接,未与常规 part 的列顺序对齐;修复后(PR #99164)在读路径中统一按目标 part 的列顺序对 patch 部件做重排/对齐,从根上消除了LOGICAL_ERROR。相关合并谓词对 patch 版本跨越的约束可进一步参考 src/Storages/MergeTree/Compaction/MergePredicates/MergeTreeMergePredicate.cpp 中“合并不得跨越既有 part 数据版本”的检查逻辑。

影响面与建议

该问题主要影响高频执行ALTER TABLE ... UPDATE/DELETE(生成 patch parts)并在短时间窗口内叠加读取的表。升级后建议对曾触发LOGICAL_ERROR的分区执行一次校验性查询或OPTIMIZE TABLE ... FINAL,确认数据可正常读取。

修复三:O_DIRECT 模式下异步读缓冲的 seek 定位错误

触发场景

ClickHouse 在磁盘 IO 中大量使用异步预读(prefetch)机制,并支持O_DIRECT直通模式(绕过页缓存,要求文件偏移与内存地址按块对齐)。此前在O_DIRECT开启且缓冲区发生过 seek 的场景下,会因偏移计算错误读到错误位置的数据(PR #99678 同时关闭了 issue #99358),影响查询结果正确性。

底层实现印证

相关实现在 src/IO/AsynchronousReadBufferFromFileDescriptor.h 与 src/IO/AsynchronousReadBufferFromFileDescriptor.cpp:

  • 类注释明确说明其“使用现成文件描述符,不负责打开/关闭文件”,内部维护prefetch_bufferinternal_buffermemory三块等长缓冲并在预读后交换;
  • required_alignment成员专门服务于O_DIRECT场景(头文件注释:"For O_DIRECT both file offsets and memory addresses have to be aligned"),其值由构造参数alignment传入;
  • seek()实现(src/IO/AsynchronousReadBufferFromFileDescriptor.cppseek函数)中,若目标位置仍在缓冲区内则仅移动pos指针;否则执行真实 seek,并存在关键分支:
    off_t seek_pos = required_alignment > 1 ? new_pos / required_alignment * required_alignment : new_pos;

    O_DIRECT下将目标偏移向下取整到对齐边界,差额记入bytes_to_ignore

  • 修复的另一处关键语义在 seek 的返回值:方法最终返回的是原始new_pos而非对齐后的seek_pos,注释指出返回seek_pos会破坏依赖返回值的调用方(如ReadBufferFromEncryptedFile)。

修复前,O_DIRECT路径下 seek 后缓冲区状态与file_offset_of_buffer_end/bytes_to_ignore的记账存在不一致,导致后续getPosition()(其实现为file_offset_of_buffer_end - (working_buffer.end() - pos) + bytes_to_ignore)与实际读位置偏差,从而读到错位数据。修复通过补齐对齐偏移的记账逻辑与返回语义,确保O_DIRECT下 seek 结果准确。

相关配置提示

O_DIRECT行为通常由存储配置(如磁盘的direct_io相关设置)或表级min_bytes_to_use_direct_io类参数控制(请以 tests/config 与 src/Disks 中的实际配置项为准)。若你的环境启用了直通 IO,本修复直接关系到读正确性,建议优先升级并针对大文件读路径做回归。

总结

v25.8.20.4-lts 是一次典型的 LTS 稳定性补丁发布:三项修复分别覆盖查询执行层(递归 CTE)MergeTree 存储层(Patch Parts)IO 基础层(O_DIRECT 异步读),均为用户可见的错误行为修复。对于运行 25.8 LTS 系列的集群,建议按变更窗口安排升级;若涉及远程分布式查询、高频轻量变更或直通 IO 场景,可结合本文给出的源码路径做针对性回归验证。

  • 发布记录原始文档:docs/changelogs/v25.8.20.4-lts.md
  • 递归 CTE 相关源码:src/Analyzer/RecursiveCTE.cpp、src/Processors/Sources/RecursiveCTESource.cpp、src/Processors/QueryPlan/ReadFromRecursiveCTEStep.cpp
  • Patch Parts 变更转换源码:src/Storages/MergeTree/AlterConversions.cpp、src/Storages/MergeTree/AlterConversions.h
  • O_DIRECT 异步读缓冲源码:src/IO/AsynchronousReadBufferFromFileDescriptor.cpp、src/IO/AsynchronousReadBufferFromFileDescriptor.h

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

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

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

YOLO v5到v11全解析:选型策略与实战部署指南

YOLO 系列走到今天&#xff0c;已经从一个单纯的实时检测算法&#xff0c;变成了一套覆盖检测、分割、姿态估计、旋转框、跟踪的完整工具箱。从 v5 到 v11&#xff0c;这个开源生态经历了多次架构级别的重塑&#xff0c;很多初学者问我的第一句话就是&#xff1a;现在到底该学哪…

作者头像 李华
网站建设 2026/9/18 22:11:24

用Altium Designer生成交互式BOM:三种方案与工程实践

1. 交互式BOM是什么&#xff0c;它到底解决了什么问题做PCB设计到现在快十年&#xff0c;最让我烦躁的除了改版&#xff0c;就是交BOM表。早年间给产线、给采购、给贴片厂发BOM&#xff0c;打开Excel从头翻到尾&#xff0c;对方还是要反复打电话问“R12在板子哪个位置”“这个电…

作者头像 李华
网站建设 2026/9/18 22:11:16

个人微信API接口如何承接AI搜索流量?GEO时代微信私域的应用新思路

GEO内容让品牌出现在AI的回答里&#xff0c;这只是获客的前半段。用户通过AI了解品牌后要进入微信私域&#xff0c;后半段的承接如果接不住——加了好友没人理、来源分不清、转化算不清账——前半段的内容投入就浪费了。承接是一条独立的运营链路&#xff0c;有四个关键环节。一…

作者头像 李华