ClickHouse v22.11.6.44-stable 发布说明详解:Array 列查询性能、垂直合并内存行为与 c-ares 段错误根因分析
2026/9/13 18:59:06 网站建设 项目流程

ClickHouse v22.11.6.44-stable 发布说明详解:Array 列查询性能、垂直合并内存行为与 c-ares 段错误根因分析

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

本文基于 ClickHouse 仓库中的发布说明 v22.11.6.44-stable 展开,逐条解读该版本相对上一稳定版 v22.11.5.15-stable 的全部变更(均为 backport 回移提交),并结合当前仓库源码佐证其中的性能优化点与缺陷修复原理。读完本文,你可以理解该版本对Array/Map/Nested列短查询性能、垂直合并(vertical merge)内存行为、DNS 解析器c-ares段错误等关键问题的具体处理,以及如何在 22.11 分支上正确升级与验证。

版本定位:一个纯回移(Backport)性质的 22.11 稳定版

该版本的发布说明标题为:

ClickHouse release v22.11.6.44-stable (73ddf91298f) as compared to v22.11.5.15-stable (d763e5a9239)

其中73ddf91298f是 v22.11.6.44-stable 的构建提交哈希,d763e5a9239是上一版本 v22.11.5.15-stable 的哈希。发布说明中每一条变更都标注了 “Backported in #xxxxx”,说明这些修复最初合入 master 分支(对应 PR 编号),再回移到 22.11 维护分支后随本版本发布。对运行在 22.11 LTS 分支上的集群而言,这是获取上述缺陷修复与性能改进的正式途径。

性能改进(Performance Improvement)

修复从大量 Array/Map/Nested 列读取的短 SELECT 查询性能

  • 对应上游 PR #45630(回移跟踪 #45703),作者 Anton Popov。

问题背景:当表含有较多ArrayMapNested类型列时,即使是SELECT count() FROM table这类不读取列数据的短查询,也可能因元数据/列处理路径的开销而变慢。这类列在底层由多个物理列构成(Nested会被展开为多列,Map拆分为 key/value 两列),列数膨胀会放大元数据扫描成本。该修复优化了此类场景下短查询的执行路径,避免不必要的列处理开销。

从源码结构看,当前仓库中 MergeTree 的表元数据与列映射逻辑集中在 src/Storages/MergeTree/MergeTreeData.cpp 与列解析相关模块中,Nested/Map的物理列展开机制依然存在,因此这类“元数据敏感型”性能问题在列数很多的宽表上值得持续关注。

修复非远程盘上垂直合并内存占用过大的问题,并让远程盘遵循 max_insert_delayed_streams_for_parallel_write

  • 对应上游 PR #46275(回移跟踪 #46376),作者 Nikolai Kochetov。
  • 变更说明原文:“Fix too big memory usage for vertical merges on non-remote disk. Respectmax_insert_delayed_streams_for_parallel_writefor the remote disk.”

这是本版本值得深入理解的一处改动,它涉及两个相关概念:

  1. 垂直合并(Vertical Merge)与流式写入:垂直合并按“列组(stream)”分批处理列,每个 stream 独立读取、转换并写入,以降低峰值内存。MergeTree 表引擎设置中有与之配套的参数,当前仓库的 src/Storages/MergeTree/MergeTreeSettings.cpp 中定义了合并侧的同源设置:

    DECLARE(UInt64, max_merge_delayed_streams_for_parallel_write, 40, R"( The maximum number of streams (columns) that can be flushed in parallel (analog of max_insert_delayed_streams_for_parallel_write for merges). Works only for Vertical merges. )", 0)

    即垂直合并最多允许 40 个 stream 并行 flush(默认值),这与写入侧的max_insert_delayed_streams_for_parallel_write(控制 INSERT 时并行写列流的数量)互为镜像。

  2. 非远程盘的内存修复与远程盘的流数上限:修复前,使用本地(非远程)盘的垂直合并可能产生过大的内存占用;同时远程盘(如 S3 对象存储后端)路径没有正确遵循max_insert_delayed_streams_for_parallel_write限制,可能同时打开过多的并行写入流。该修复保证两类场景下的流并行度都受该设置约束,从而把内存峰值控制在可预期范围内。

从源码结构看,并行写入流的调度实现在 src/Storages/MergeTree/MergeTreeSink.cpp 与 src/Storages/MergeTree/MergeTask.cpp 中,max_insert_delayed_streams_for_parallel_write在这两个文件以及 src/Core/Settings.cpp 中均有解析与使用逻辑,与发布说明描述的“让远程盘也尊重该设置”一致。对使用大宽表并开启了vertical_merge的用户,升级到本版本后可观察合并任务的内存占用(如system.parts与合并 profile 事件)是否回落。

缺陷修复(Bug Fix)

1. 表元数据中 EPHEMERAL 列默认值不可解析的 Bug

  • 对应上游 PR #44026(回移跟踪 #45903),作者 Yakov Olkhovskiy。

修复“表元数据中EPHEMERAL列的默认值无法被解析”的问题。EPHEMERAL是 ClickHouse 支持的列属性:列值只存在于内存中、不持久化到数据 part,重启后按默认值重建,适合缓存型字段。当列定义携带EPHEMERAL DEFAULT ...时,元数据序列化/反序列化路径需要能正确解析默认值表达式;此前某些默认值写法会导致解析失败。修复后元数据读写路径对EPHEMERAL列默认值的处理变得健壮。从源码结构看,ZooKeeper 侧对EPHEMERAL节点的区分逻辑集中在 src/Common/ZooKeeper/ZooKeeperCommon.cpp 等文件中,而表元数据层面的列属性解析位于src/Core/src/Interpreters/的表元数据模块中,二者共同构成该修复的验证面。

2. c-ares 周边段错误(segfault)根因定位:poll 的 EINTR 被误判为失败

  • 对应上游 PR #45629(回移跟踪 #46239),作者 Arthur Passos。

这是发布说明中描述最详细的一条,值得完整理解其因果链:

  1. 多个用户报告围绕c-ares(ClickHouse 使用的异步 DNS 解析库)出现段错误,且近来的栈信息都崩在往std::unordered_set<>插入的位置。
  2. 根因是“未处理完的查询”:ClickHouse 使用poll等待 c-ares channel 的文件描述符就绪。按poll(2)的语义,负返回值表示出错,但poll在收到系统中断(EINTR)时同样返回负值——系统中断并不意味着请求失败或结束。
  3. 旧代码只检查“返回值是否为负”就判定失败并中止本次解析执行。中止后整个调用栈被销毁,其中包括作为void *参数传给 c-ares 回调的std::unordered_set<std::string>
  4. 之后 c-ares 真正完成请求时仍会触发回调,回调访问到已被销毁的集合对象,于是在向std::unordered_set插入时解引用悬垂指针,造成段错误。

当前仓库中该修复的形态可以直接看到:src/Common/CaresPTRResolver.cpp 的等待循环对poll负返回值做了区分处理——

int number_of_fds_ready = poll(dns_state.poll_fds, static_cast<nfds_t>(dns_state.poll_nfds), static_cast<int>(timeout)); if (number_of_fds_ready < 0) { if (errno == EINTR) continue; // 系统中断:不是错误,重新进入等待循环 return false; // 真正的错误才判定失败 }

EINTRcontinue重入等待,只有其他错误才返回失败。这保证了 c-ares 回调关联的用户数据在其生命周期内始终有效,从根源上消除了发布说明中描述的“栈销毁后回调野访问”路径。该组件主要用于 PTR(反向 DNS)解析,影响面包括依赖主机名解析的连接路径,属于稳定性修复,升级无兼容性负担。

3. 修复在 Compact part 中读取多级不存在嵌套列的问题

  • 对应上游 PR #46045(回移跟踪 #46216),作者 Azat Khuzhin。

修复在Compact格式数据 part 中读取多级不存在的嵌套列(multi-level non-existing nested columns)的问题。Compactpart 是 MergeTree 面向小数据量 part 的列合并存储格式(由 src/Storages/MergeTree/MergeTreeSettings.cpp 中min_level_for_wide_part/min_rows_for_wide_part/min_bytes_for_wide_part等参数控制生成)。此前当查询引用了表结构中不存在的深层嵌套列(如a.b.ca.b不存在)时,Compact part 的读取路径会出错;修复后该场景按“缺失列返回默认值/正常报错”的预期行为处理。

4. 修复异步插入(asynchronous inserts)收到非法 VALUES 数据时的 LOGICAL_ERROR

  • 对应上游 PR #46350(回移跟踪 #46444),作者 Anton Popov。

当开启async_insert后,客户端以VALUES格式提交的数据若在内部二次解析时不合法,旧代码会抛出LOGICAL_ERROR(逻辑错误,通常意味着内部断言失败而非用户输入问题)。修复后该场景按数据错误正常处理,不再误报内部逻辑错误。使用异步插入功能(INSERT 语句配合async_insert=1或 flush 时机配置)的用户应升级以避免此类误报。

5. 修复 arrayMap 对常量 LowCardinality 参数的错误处理

  • 对应上游 PR #46569(回移跟踪 #46676),作者 Alexey Milovidov。

arrayMap函数在处理常量的LowCardinality类型参数时处理逻辑有误:在 release 构建中可能直接导致段错误,在 debug 构建中则抛出Bad cast逻辑错误。这属于类型推断/常量折叠路径上的错误转换问题,修复后arrayMap对常量LowCardinality参数的处理恢复正常。对使用了LowCardinality(String)等类型并经常配合arrayMap/array函数族的查询,此修复直接消除一类崩溃隐患。

构建 / 测试 / 打包改进(Build/Testing/Packaging Improvement)

ZooKeeper 下载修复、版本更新与镜像瘦身

  • 对应上游 PR #44853(回移跟踪 #45977),作者 Mikhail f. Shiryaev。

修复 CI/打包流程中 ZooKeeper 依赖的下载问题,更新其版本并优化镜像体积。对最终用户而言主要体现为官方构建产物的下载渠道更稳定、构建镜像更小。

从包中移除 adduser 工具依赖

  • 对应上游 PR #45011(回移跟踪 #46114),修复 #44934,作者 Alexey Milovidov。

说明原文:“Remove the dependency on theaddusertool from the packages, because we don't use it.” 即官方软件包不再声明对adduser命令的依赖(ClickHouse 实际并未使用它),解决了部分最小化系统(缺少adduser)上包安装/依赖检查失败的问题。当前仓库 packages/ 目录下的包定义文件(如 clickhouse-server.yaml、clickhouse-client.yaml)即为该打包体系的维护位置。

去掉 standalone clickhouse-keeper 的多余构建

  • 对应上游 PR #46367(回移跟踪 #46483),作者 Mikhail f. Shiryaev。

独立版clickhouse-keeper的构建链路中存在不必要的重复构建步骤,本提交将其移除,缩短构建耗时。

ccache 压缩包格式修正:优先下载 zst 归档

  • 对应上游 PR #46490(回移跟踪 #46507),作者 Mikhail f. Shiryaev。

说明原文指出:ccache 的压缩格式一段时间前已改为zst(zstd 压缩),但下载逻辑默认仍然取gz归档,造成格式错配。修复后优先选择zst归档,保证开发者增量编译缓存(ccache)下载可用。对应构建逻辑可参考 cmake/ccache.cmake。

其他内部变更(NOT FOR CHANGELOG)

发布说明末尾列出了一组“不计入变更日志”的内部改动,均面向 CI/自动化工具链,供维护者追溯:

  • #45476:再次尝试修复 automerge 流程,或至少为其留下调试痕迹(Mikhail f. Shiryaev)。
  • #45803:在merge_pr.py中增加“检查正在运行的 workflow”逻辑(Mikhail f. Shiryaev)。
  • #45818:去除发布流程中的进度时间戳(Mikhail f. Shiryaev)。
  • #45959:为 sanitizer 构建补充必要依赖(Mikhail f. Shiryaev)。
  • #46080:为自动合并脚本增加辅助日志(Mikhail f. Shiryaev)。
  • #46205:修复垂直合并中写入缓冲区(write buffer)的析构顺序(Nikolai Kochetov)——与上文垂直合并内存修复同属一个治理方向。
  • #46665:移除遗留的 DocsReleaseChecks(Mikhail f. Shiryaev)。

升级与验证建议

对 22.11 分支的生产集群,本版本的升级要点可归纳为:

  1. 崩溃类修复优先:c-aresEINTR段错误(#45629)、arrayMap常量LowCardinality段错误(#46569)都是可导致进程崩溃的隐患,若线上出现过 DNS 解析相关的std::unordered_set崩溃栈或arrayMap相关 crash,建议尽快升级至 v22.11.6.44-stable。
  2. 内存与性能观察:开启垂直合并或写入并行流(max_insert_delayed_streams_for_parallel_write)的环境,升级后建议对比合并/插入阶段的峰值内存与大Array/Map/Nested宽表上短查询的延迟。
  3. 功能行为验证:使用SELECT version()确认运行版本为22.11.6.44;对启用异步插入、EPHEMERAL列的表分别执行一次代表性 INSERT/SELECT 冒烟查询,确认无LOGICAL_ERROR/解析异常。
  4. 回移版本核对:由于本版本全部变更均为 backport,如需核对某条修复是否已进入自己基于的分支,可以对照发布说明中的上游 PR 编号在 docs/changelogs/ 下的对应版本记录中检索。

整体来看,v22.11.6.44-stable 是一次以稳定性修复为主、附带两项明确性能改进的维护版本:既堵住了 DNS 解析路径与arrayMap类型处理上的崩溃缺口,也修正了垂直合并内存与宽元数据查询的性能回归,适合作为 22.11 分支上的标准升级目标。

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

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

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

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

立即咨询