ClickHouse v24.1.6.52-stable 版本解析:从 GCP S3 读取回退到 KQL 解析器段错误修复的 24 项变更
2026/9/16 11:06:21 网站建设 项目流程

ClickHouse v24.1.6.52-stable 版本解析:从 GCP S3 读取回退到 KQL 解析器段错误修复的 24 项变更

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

本文基于 ClickHouse 官方发布记录 v24.1.6.52-stable,系统梳理 2024 年首个稳定分支 24.1 的第 6 个补丁版本中包含的改进、Bug 修复与内部工程变更,并结合当前仓库源码(src/目录)对 KQL 解析器、AsynchronousBoundedReadBufferoptimize_uniq_to_count优化、system.numbers等关键修复点做源码级解读,帮助读者理解这些修复的底层原理、受影响的模块以及升级 24.1 系列时应关注的兼容性要点。

版本背景:24.1 补丁分支的第 6 个稳定版

ClickHouse 采用「主版本 + 补丁」的双轨发布模型:主版本(如 24.1、24.3)按月推出新功能,而稳定补丁分支(-stable)只合入 Bug 修复与少量改进,追求最大稳定性。本次解析的v24.1.6.52-stable(提交号fa09f677bc9)即是 24.1 分支上相对上一补丁 v24.1.5.6-stable(提交号7f67181ff31)的增量发布。

从发布记录的结构看,本次补丁共分四个区块:

区块数量内容定位
Improvement2用户可见的功能/行为改进
Bug Fix (user-visible misbehavior)13修复官方稳定版中用户可见的异常行为
NO CL CATEGORY1未分类的变更
NOT FOR CHANGELOG / INSIGNIFICANT8内部工程变更,无用户可见影响

值得注意的是,发布记录标题带有一个FIXME标记(v24.1.6.52-stable FIXME as compared to ...),这是 ClickHouse 自动生成 changelog 时用于提醒维护者核对版本号的工程性占位符,不代表发布存在问题。

Improvement:两项面向对象存储与时区的改进

1. S3 文件复制:GCP 网关超时回退到缓冲复制

当从 S3 复制文件且后端为GCP(Google Cloud Storage)时,如果 GCP 返回了带有GATEWAY_TIMEOUT(HTTP 504)错误码的Internal Error,ClickHouse 会回退到缓冲复制方式(buffer copy)。该变更由 PR #60164 引入,用于提升跨云对象存储复制操作的健壮性。

结合仓库源码可以理解这一改动的技术背景:ClickHouse 的对象存储层同时支持"流式复制"与"缓冲复制"两种路径,其中 S3 相关的读写逻辑集中在 src/IO/ReadBufferFromS3.cpp、src/Disks/DiskObjectStorage/ObjectStorages/S3/S3ObjectStorage.cpp,磁盘对象存储的复制实现位于 src/Disks/DiskObjectStorage/DiskObjectStorage.cpp。GCP 的 S3 兼容网关在压力下偶发 504,若流式复制无法容错,回退到缓冲复制可以在牺牲一定内存开销的前提下保证复制任务的最终成功,属于典型的"降级不降可用性"策略。

2. tzdata 时区数据库升级到 2024a

本次补丁将内置的tzdata(IANA 时区数据库)升级到 2024a版本(PR #60768)。时区数据直接关系到toDateTimetoTimeZonetoStartOfHour等所有与时区相关函数的计算结果,以及DateTime类型的timezone参数解析。升级后,服务器内置的system.time_zones表内容也会随之刷新,保证夏令时规则、政区时区变更等信息与 IANA 官方同步。对于跨时区报表、日志时间归一等场景,建议升级后主动复核依赖具体时区规则的查询结果。

Bug Fix:13 项用户可见问题修复逐一解读

KQL 解析器:超长查询段错误与方言重新启用

修复内容:当输入查询超过max_query_size限制时,KQL(Kusto Query Language)解析器会发生段错误(segmentation fault);修复后还重新启用了 KQL 方言。该问题对应 issue #59036、#59037,由 PR #59626 修复。

源码印证:KQL 是 ClickHouse 为兼容 Azure Data Explorer 查询语法而内置的方言,其解析链路分布在 src/Parsers/Kusto/ 目录,包括KQLLexer.cppKQLParser.cppparseKQLQuery.cppKQLTranslator.cpp等文件。段错误通常源于词法/语法分析阶段对超长输入缓冲的错误边界处理——查询长度超过max_query_size时缓冲区被截断或越界访问。

关联配置max_query_size在 src/Core/Settings.cpp 中定义(默认值DBMS_DEFAULT_MAX_QUERY_SIZE)。该设置有一个重要特性:它不能在 SQL 查询内部动态设置(例如SELECT now() SETTINGS max_query_size=10000是无效的),因为 ClickHouse 需要先按该值分配解析缓冲区,缓冲大小必须在查询执行前确定。因此若业务存在超长 KQL 查询,只能在config.xml<max_query_size>或用户/配置文件中预先调大。

异步有界读缓冲:修复 "Read beyond last offset"

修复内容:修复AsynchronousBoundedReadBuffer可能抛出Read beyond last offset错误的问题(PR #59630)。

源码印证AsynchronousBoundedReadBuffer是 ClickHouse 远程文件系统(S3、HDFS 等)读取路径中的核心组件,定义于 src/Disks/IO/AsynchronousBoundedReadBuffer.h。从类结构可以看出其设计要点:

  • 继承ReadBufferFromFileBase并实现IReadBufferMetadataProvider,同时承担顺序读与元数据读取;
  • 通过readAsync/readSync双路径配合IAsynchronousReader实现异步预取(prefetch),prefetch_bufferprefetch_future管理在途预取任务;
  • read_until_positionbytes_to_ignore等成员用于约束读取范围——"Read beyond last offset" 正是读取范围计算在并发预取场景下越过文件末尾引发的错误;
  • 支持setReadUntilPosition/setReadUntilEnd精确限定读取边界,这与修复"读越界"问题的方向直接相关。

该组件的单元测试位于 src/Disks/tests/gtest_asynchronous_bounded_read_buffer.cpp 和 src/IO/tests/gtest_readbuffer_s3.cpp,可用于回归验证。

Kafka 引擎:读-写阶段异常时消息既不 ack 也不 nack 的修复

修复内容:修复了 Kafka 表引擎在读-写阶段(read-write phase)发生异常时,消息既没有被 ack 也没有被 nack的问题(PR #59775)。修复后,异常路径下消息会被正确nack,从而可以重新消费,避免消息静默丢失。

该修复对使用 Kafka 引擎做实时数仓同步的场景至关重要:如果消息既未确认也未否认,Kafka 消费位点不会推进,可能导致重复消费或消费中断;统一 nack 保证了失败重试的可预期性。

查询优化器:optimize_uniq_to_count丢失列别名

修复内容:修复optimize_uniq_to_count优化在改写查询时删除列别名(column alias)的问题(PR #60026)。该问题会导致结果列名不符合预期(例如SELECT uniq(x) AS u改写后u别名丢失)。

源码印证:该优化实现在 src/Analyzer/Passes/UniqToCountPass.cpp 中,其核心逻辑(UniqToCountVisitor)如下:

  1. optimize_uniq_to_count设置开关控制(定义于 src/Core/Settings.cpp);
  2. 仅匹配uniquniqHLL12uniqExactuniqThetauniqCombineduniqCombined64六种去重聚合函数;
  3. 仅当外层查询满足"单一uniq投影 + FROM 子查询为SELECT DISTINCTGROUP BY"且参数列表与子查询投影列/分组列完全一致时,才把uniq(...)改写为count(...)
  4. 值得注意的是,源码对NULL 语义做了精细处理:uniq不计 NULL,而无参count()会计数 DISTINCT 产生的 NULL 行,因此当参数可能包含 NULL 时,改写为count(x)(单参数,保持跳过 NULL 的语义);多参数uniq(x, y)无法找到等价 NULL 语义,拒绝改写;同时显式排除ROLLUP/CUBE/WITH TOTALS/GROUPING SETS等会产生超聚合行的场景。

别名丢失正是发生在第 3 步改写(resolveAggregateFunctionNodeByName(*function_node, "count"))过程中,本次修复保证了函数节点被替换为count后别名节点依然保留。

FINAL 并行优化:罕见场景下的错误结果

修复内容:修复带FINAL修饰符的查询在并行优化时可能产生错误结果的罕见问题(PR #60041)。FINAL用于强制合并ReplacingMergeTreeCollapsingMergeTree等引擎的重复行,其并行化对行序与合并语义要求极高,任何并发放大都会造成结果偏差。该修复提醒使用者:在升级后如遇FINAL查询结果变化,属于正确性回归修复而非行为变更。

cosineDistance:Nullable 参数导致崩溃

修复内容:修复cosineDistance函数在参数为Nullable类型时崩溃的问题(PR #60150)。

源码印证cosineDistance是向量相似度计算函数,其实现位于 src/Functions/array/arrayDistance.cpp,并与其他向量函数共用 src/Functions/vectorFunctions.cpp 中的基础设施。崩溃根因可推断为Nullable包装层(Nullable列或Nullable数组元素)在向量化计算时未正确解包,导致对空值/空数组执行了非法的数值运算。修复方向通常是先解包Nullable再进入向量化内核,或对空输入显式返回 NULL。

S3Queue 表引擎:隐藏敏感信息

修复内容:修复S3Queue表引擎在错误信息、系统日志等场景中泄露敏感信息的问题(PR #60233)。

源码印证S3Queue是 ClickHouse 基于对象存储的消息队列表引擎,核心实现在 src/Storages/ObjectStorageQueue/,包括StorageObjectStorageQueue.cppStorageObjectStorageQueue.hObjectStorageQueueMetadata.cpp等,并注册于 src/Storages/ObjectStorageQueue/registerQueueStorage.cpp。S3 连接通常携带access_key_id/secret_access_key等凭证,若异常信息或系统表直接输出完整 S3 URL(含查询参数中的签名),将造成凭证泄露。该修复属于安全加固,升级后建议同步检查system.query_log中与 S3Queue 相关的异常信息是否已脱敏。

system.numbers:减少读取行数

修复内容:减少从system.numbers系统表读取的行数(PR #60546,修复 issue #59418)。system.numbers是一个无限序列表(实现于 src/Storages/System/StorageSystemNumbers.cpp),常用于生成测试数据或模拟行号。此前某些查询路径可能对system.numbers产生超预期的大量读取,本次修复优化了其读取逻辑,降低不必要的 I/O 开销。

HTTP 服务器解压:组合编解码器的缓冲区溢出

修复内容(安全类,重点):修复两类缓冲区溢出:

  1. HTTP 服务器解压路径:攻击者可通过组合多个编解码器(codec)并构造触发数值溢出的尺寸参数,造成缓冲区溢出;
  2. codec NONE:在错误输入数据下内部发生缓冲区溢出。

该问题由 TIANGONG 研究团队通过 ClickHouse 的 Bug Bounty 项目提交(对应 issue #38986),由 PR #60731 修复。这是本次发布中最值得关注的安全修复,涉及 HTTP 接口的数据解压与压缩编解码层(相关代码位于 src/Compression/),建议所有暴露 HTTP 端口的实例尽快升级

SQL/JSON 函数:读取未初始化内存

修复内容:修复 SQL/JSON 相关函数可能读取未初始化内存的问题(PR #60738,关闭 issue #60017),由 Fuzzer(模糊测试)发现。未初始化内存读取属于典型的内存安全缺陷,可能导致不确定行为或信息泄露。SQL/JSON 函数位于 src/Functions/JSON 与 src/Formats 相关目录,涉及 JSONPath 求值、JSONExtract系列函数等。

S3 上传:移除 UploadPart 与 CompleteMultipartUpload 上的 x-amz-meta-* 头

修复内容:不再在UploadPartCompleteMultipartUpload调用中设置 AWS 自定义元数据头x-amz-meta-*(PR #60748)。S3 分片上传时,x-amz-meta-*元数据只在CreateMultipartUpload阶段有意义,后续分片与完成阶段携带这些头可能被部分 S3 兼容服务拒绝或产生意外行为。该修复消除了多云(非 AWS 的 S3 兼容存储)上传的兼容性问题。

arrayEnumerateRanked:崩溃修复

修复内容:修复arrayEnumerateRanked函数的崩溃问题(PR #60764)。该函数用于对数组元素进行带排名(rank)的枚举,实现在 src/Functions/array/arrayEnumerateRanked.cpp,并与其变体arrayEnumerateDenseRankedarrayEnumerateUniqRanked共享实现(见 src/Functions/array/arrayEnumerateDenseRanked.cpp、src/Functions/array/arrayEnumerateUniqRanked.cpp)。崩溃场景可推断为边界输入(如空数组、rank 参数越界)在递归/循环枚举逻辑中访问越界,修复后建议对边界输入补充测试。

INSERT SELECT JOIN 中使用 input():崩溃修复

修复内容:修复在INSERT SELECT ... JOIN中使用input()函数导致的崩溃(PR #60765,关闭 issue #60035)。input()用于在 INSERT 中引用外部输入流数据,当与 JOIN 组合时,输入流的数据管道结构复杂化,本次修复保证了该组合场景下的稳定性。

S3 读取:跳过过多 key 时的段错误

修复内容:修复从 S3 读取时跳过(skip)过多 key导致的段错误(PR #60849)。在 glob 匹配或前缀枚举场景下,若被跳过的对象数量巨大,相关计数/指针逻辑可能出现溢出或越界,本次修复补上了对应防护。

内部工程变更(NOT FOR CHANGELOG / INSIGNIFICANT)

这部分变更不直接影响用户可见行为,主要面向 CI 与运维基础设施:

  • CI:Jepsen 测试工件导致的 job 失败修复(PR #59890);
  • CI:修复 release ready 标记逻辑(PR #59994);
  • 检测"僵尸" ZooKeeper 会话(PR #60044):增加对 ZooKeeper 会话存活性探测能力,可识别已死但未及时清理的会话,对分布式协调稳定性有意义;
  • CI:gh statuses 热修复(PR #60201);
  • 测试:检测 io_uring 支持情况(PR #60373):在测试中探测内核 io_uring 可用性,避免不支持环境下的误报;
  • 移除一个待修复的损坏测试(PR #60547);
  • 更新 shellcheck 静态检查工具(PR #60553);
  • CI:修复 docker build job 名称(PR #60554)。

升级建议与验证要点

基于以上变更,对升级到 v24.1.6.52-stable(或后续 24.1 补丁)的实例给出如下建议:

  1. 安全优先级最高:涉及 HTTP 解压缓冲区溢出(TIANGONG 提交)与 SQL/JSON 未初始化内存读取两项内存安全修复,公网暴露的实例应优先升级;
  2. 重点关注对象存储场景:若使用 GCP S3 兼容端点(关注 504 回退)、S3 分片上传(关注x-amz-meta-*头)或 S3Queue(关注敏感信息脱敏),升级后建议回归相关 COPY、INSERT 与队列消费链路;
  3. KQL 用户注意:KQL 方言被重新启用,超长查询不再段错误;若曾因崩溃而禁用 KQL,升级后可恢复使用,并注意max_query_size需在查询外配置(见 src/Core/Settings.cpp);
  4. 时区相关查询:tzdata 升级到 2024a 后,涉及历史夏令时规则或政区时区调整的查询结果可能变化,建议核对;
  5. 查询正确性FINAL并行优化、optimize_uniq_to_count两处修复可能改变改写后的执行计划与结果列名,建议对依赖FINALuniq别名的报表做回归验证。

延伸阅读

  • 完整发布记录:v24.1.6.52-stable(位于 docs/changelogs/archive/ 目录,该目录收录 696 份历史版本记录)
  • KQL 解析器源码:src/Parsers/Kusto/
  • 异步有界读缓冲实现与测试:src/Disks/IO/AsynchronousBoundedReadBuffer.h、src/Disks/tests/gtest_asynchronous_bounded_read_buffer.cpp
  • optimize_uniq_to_count优化实现:src/Analyzer/Passes/UniqToCountPass.cpp
  • S3Queue 表引擎:src/Storages/ObjectStorageQueue/
  • max_query_size设置定义:src/Core/Settings.cpp
  • system.numbers系统表:src/Storages/System/StorageSystemNumbers.cpp

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询