ClickHouse v22.12.4.76-stable 版本解析:一次聚焦合并内存、远端存储与 Keeper 打包的补丁发布
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
本文以 v22.12.4.76-stable 变更日志 为主体,完整梳理这一 22.12 LTS 分支补丁版本的全部改动,并结合当前仓库中的设置定义、systemd 单元文件与协调模块源码,解释每项修复背后的机制:读者将掌握该版本在垂直合并(vertical merge)内存控制、c-ares DNS 段错误根因、Keeper 表 EPHEMERAL 元数据修复、以及 clickhouse-keeper 独立打包等关键问题上的具体表现与升级价值。
版本定位
该版本发布于 2023 年,对比基线为v22.12.4.76-stable(commitcb5772db805)对 v22.12.3.5-stable(commit893de538f02),属于 22.12 分支上的稳定线补丁版本(stable patch release)。从变更日志的结构看,所有条目均标注 "Backported in #xxxxx",意味着这些改动并非在 22.12 上原生开发,而是从 master 分支回合(backport)而来——这是 ClickHouse 补丁版本的典型模式:master 修复问题后,维护者把对应的 PR 回合到各 LTS 分支,再按类别归入 Performance Improvement、Bug Fix、Build/Testing/Packaging 等小节。
对生产用户而言,这个版本的核心价值集中在三处:远端存储场景下的写入内存控制、c-ares 引发的偶发段错误、以及 clickhouse-keeper 作为独立组件的部署能力。下面逐项展开。
性能改进
大量 Array/Map/Nested 列上短 SELECT 的性能回退修复
变更日志第一条(Backported in #45704,原始修复 PR #45630,作者 CurtizJ):修复从包含大量Array/Map/Nested列的表中读取时,短SELECT查询的性能问题。
这类表在列式存储中每个逻辑列会被展开成多条子流(substream),读取路径需要处理更多列描述符与偏移量;当查询只触及少量列且数据量很小时,这部分元数据处理的固定开销会明显拉低短查询的延迟。该修复降低了此类场景下的读取开销,对于以 Map/嵌套结构建模日志、标签、KV 数据(这类模式在 ClickHouse 中非常常见)的实例尤为值得升级验证。
垂直合并在非远端磁盘上的内存占用修复
第二条(Backported in #46378,原始 PR #46275,作者 KochetovNicolai):修复非远端磁盘上垂直合并(vertical merge)内存占用过大的问题,并让远端磁盘遵守max_insert_delayed_streams_for_parallel_write设置。
这两句分别对应两个问题:
- 本地(非远端)磁盘上的垂直合并不应采用"延迟 flush 各列流"的远端优化策略,此前的实现使内存占用过大;
- 远端磁盘(如 S3)上延迟 final flush 的并行流数量此前不受约束,现在会受到
max_insert_delayed_streams_for_parallel_write限制。
在当前仓库的 Settings.cpp 中可以看到该设置的定义:
DECLARE(UInt64, max_insert_delayed_streams_for_parallel_write, 0, R"( The maximum number of streams (columns) to delay final part flush. Default - auto (100 in case of underlying storage supports parallel write, for example S3 and disabled otherwise) Cloud default value: `50`. )", 0)从这段源码定义可以确认:默认值为0,即"自动"——当底层存储支持并行写(例如 S3)时取 100,否则禁用延迟 flush。这正是 v22.12.4.76 修复所针对的行为:修复前远端磁盘上的并行流数量"不尊重"该设置,修复后本地磁盘回退到更省内存的合并策略、远端磁盘按设置约束并行度。如果你的表列数很多(例如几百列)且写入路径涉及远端存储或垂直合并,这一条直接决定了 INSERT/merge 期间的峰值内存。
Bug 修复(用户可见)
变更日志将用户可见的严重缺陷单列为 "Bug Fix (user-visible misbehavior in official stable release)",共 10 项,是本次补丁的修复主体。
Keeper 表 EPHEMERAL 列默认值不可解析
Backported in #45904(原始 PR #44026,作者 yakov-olkhovskiy):修复表元数据中 EPHEMERAL 列默认值不可解析(non-parsable default value)的缺陷。
这是 ClickHouse Keeper(与 ZooKeeper 兼容的分布式协调组件,可承载Replicated*表引擎的元数据)的问题:Keeper 在表引擎元数据里保存的节点属性包含一个 EPHEMERAL 标志位及其关联的 owner 值,若默认值序列化/反序列化不正确,读取表结构时就会报"默认值不可解析"。当前仓库的 KeeperCommon.h 保留了该机制的定义:
static constexpr uint64_t EPHEMERAL = 1ull << 63; static constexpr uint64_t FLAGS_MASK = EPHEMERAL | TTL | CONTAINER; /// ephemeralOwner value for container nodes (matches `CONTAINER_EPHEMERAL_OWNER` in ZooKeeper). static constexpr int64_t CONTAINER_EPHEMERAL_OWNER = INT64_MIN;可以看到 EPHEMERAL 是节点ctime_and_flags中的最高位标志,还专门保留了与 ZooKeeper 对齐的CONTAINER_EPHEMERAL_OWNER常量(INT64_MIN)以维持与原生 ZooKeeper 的数据兼容——这类兼容性正是该默认值修复要保证的边界之一。若你的Replicated*表曾出现表结构读取报错,升级到该版本后可消除。
CREATE TABLE 中 DEFAULT 表达式的规范化缺陷
Backported in #45321(原始 PR #44547,作者 tavplubix):修复CREATE TABLE语句中DEFAULT表达式规范化的缺陷——in函数的第二个参数(或IN运算符的右操作数)可能在 CREATE 执行期间被其求值结果替换(修复 #44496)。
这是一类典型的"建表期提前常量折叠"缺陷:列默认值表达式在持久化进表元数据前应先规范化,但规范化过程错误地对x IN (expr)的右侧执行了求值替换,导致建出的表默认值语义与用户书写不一致。对于依赖DEFAULT (expr IN (...))之类语法的建表脚本,该修复保证了元数据落盘表达式与预期一致。
远端文件系统的 LowCardinality 字典 "Cannot read all data"
Backported in #45000(原始 PR #44875,作者 KochetovNicolai):从远端文件系统读取LowCardinality字典时可能出现的Cannot read all data错误的又一个修复(修复 #44709)。
日志用词 "Another fix" 表明这是同一读路径上的连续修复:低基数字典从磁盘加载时按分块读取序列化数据,远端文件系统上的 IO 边界处理不当会导致"未读全数据"错误。如果你的字典加载自 S3/HDFS 等远端存储且使用LowCardinality键或值类型,该修复属于必升级项。
system.dictionaries 在坏结构字典下的异常
Backported in #45553(原始 PR #45399,作者 aalexfvk):当存在结构非法的字典(例如 XML 配置中类型写错)时,SELECT ... FROM system.dictionaries会抛异常的缺陷。
从行为上看,系统表本应"只读地列出字典",不应因某个字典配置错误而整体不可查。该修复让system.dictionaries对损坏结构容错,便于在字典配置出错时仍能用它做诊断——这在排障场景下很实用。
c-ares 段错误:poll 返回值处理与悬垂回调
Backported in #46226(原始 PR #45629,作者 arthurpassos):变更日志给出了完整的根因分析,值得完整理解,因为它展示了 DNS 解析路径上一个隐蔽的并发缺陷链条:
- ClickHouse 使用 c-ares(仓库中以 contrib/c-ares 形式内置)做 DNS 解析,此前通过
poll等待 c-ares channel 的文件描述符; - 按
poll(2)手册,负返回表示出错,旧代码据此中断解析; - 但
poll被系统中断(如信号)时也会返回负值——中断并不代表失败,却被误判为失败并中止执行; - 执行中止后整个调用栈被销毁,其中包括传给 c-ares 回调的
void *参数——一个std::unordered_set<std::string>; - 当 c-ares 稍后完成请求并回调时,访问到已销毁的栈上内存,触发段错误。
日志中"多个围绕 c-ares 的段错误报告、栈都落在向std::unordered_set<>插入"的描述与这条链完全吻合:远端表引擎、Kafka/S3 等需要 DNS 解析的场景在收到信号(例如查询被中断、SIGCHLD 等)后小概率崩溃。若你的实例使用远端依赖且出现过无法稳定复现的段错误,这一修复应重点纳入升级原因。
compact part 中多级嵌套列的读取
Backported in #46218(原始 PR #46045,作者 azat):修复 compact part(紧凑格式数据块)中读取多层嵌套、且实际不存在的列的缺陷。
MergeTree 的 compact part 把所有列打包存储,读取时按列索引定位;当Nested/Array(Tuple)等多级路径中某个子列缺失时,旧逻辑会错误定位。对大量小 part 未合并的表读取深层嵌套列的场景,该修复避免了误读/报错。
异步插入 + VALUES 非法数据的 LOGICAL_ERROR
Backported in #46446(原始 PR #46350,作者 CurtizJ):修复异步插入(asynchronous insert)在VALUES格式发送非法数据时可能出现LOGICAL_ERROR的缺陷。
异步插入把数据先入内存队列、后台批量落盘,解析错误本应以常规的查询错误形式返回,而非触发内部逻辑错误。该修复规范了错误传播路径,减少后台线程抛出未预期异常的可能。
arrayMap 常量 LowCardinality 参数处理
Backported in #46678(原始 PR #46569,作者 alexey-milovidov):修复arrayMap函数中常量LowCardinality参数处理不当的问题——release 构建下可能导致段错误,debug 构建下报Bad cast逻辑错误。
arrayMap对低基数数组元素做映射时,若参数是常量 LowCardinality 列,旧路径的类型转换(cast)选择错误。这是纯函数求值层的缺陷,任何使用arrayMap处理低基数数组标签/枚举类字段的查询都可能受影响,且崩溃行为说明严重度不低。
Map 数据类型缺陷
Backported in #46872(原始 PR #46856,作者 alexey-milovidov):修复Map数据类型的一个缺陷(关闭 #46855)。Map在存储与求值中都展开为Array(Tuple(key, value)),该修复属于底层类型行为的稳定性修正,使用 Map 类型承载 KV 数据的实例建议跟进升级。
LIKE 谓词中引号包裹的非 LIKE 元字符
Backported in #46954(原始 PR #46875,作者 rschu1ze):修复可翻译为子串搜索(substring search)的 LIKE 谓词中,引号内的非 LIKE 元字符结果错误的缺陷。
谓词下推会把部分LIKE改写为更高效的子串匹配;当模式串里通过引号/转义把*、?等字符"字面化"后,下推路径对字符语义的判断有误,导致匹配结果与标准 LIKE 不一致。该修复保证子串下推与原始 LIKE 语义一致,属于正确性修复,而非性能优化。
日志敏感信息擦除修复
在通用 "Bug Fix" 小节中,Backported in #45672(原始 PR #45603,作者 vitlibar):修复日志中敏感信息擦除(wiping sensitive info in logs)的缺陷。
ClickHouse 会在日志中自动抹掉查询里可能携带的敏感片段(如凭据),该修复让擦除逻辑正确生效。对把查询日志用于审计或合规留存的部署,这是安全相关修复。
构建 / 测试 / 打包改进
这一小节共 6 项,多数影响 CI 与打包产物,但其中两项直接涉及最终交付形态:
clickhouse-keeper 的 systemd 服务文件
Backported in #46035(原始 PR #45568,作者 Felixoid):为 clickhouse-keeper 增加 systemd.service 文件(修复 #44293)。
这正是当前仓库 packages/clickhouse-keeper.service 的来源。该单元文件的关键配置包括:
[Service] Type=simple User=clickhouse Group=clickhouse Restart=always RestartSec=30 ExecStart=/usr/bin/clickhouse-keeper --config=/etc/clickhouse-keeper/keeper_config.xml --pid-file=%t/%p/%p.pid LimitCORE=infinity LimitNOFILE=500000 CapabilityBoundingSet=CAP_NET_ADMIN CAP_IPC_LOCK CAP_SYS_NICE CAP_NET_BIND_SERVICE从这份单元文件可以读出 keeper 独立部署的约定:独立可执行文件/usr/bin/clickhouse-keeper、独立配置目录/etc/clickhouse-keeper/keeper_config.xml、以clickhouse用户运行、崩溃后 30 秒自动重启,并设置了与 server 相当的文件描述符上限(keeper 作为协调服务连接数不少)。配套的安装后脚本 packages/clickhouse-keeper.postinstall 负责创建用户/组、目录权限,并在存在 systemd 时enable clickhouse-keeper。在此之前,keeper 随 server 打包却缺少独立服务单元,单独部署 keeper 集群(例如为多个 ClickHouse 集群提供共享协调服务)的用户受影响最大。
其余打包与 CI 修复
- 移除对
adduser工具依赖(Backported in #46116,原始 PR #45011,作者 alexey-milovidov):软件包不再依赖发行版可能未预装的adduser工具,修复 #44934,改善了在精简发行版上安装包的兼容性; - 去掉独立 clickhouse-keeper 的多余构建(Backported in #46484,原始 PR #46367,作者 Felixoid):精简 CI 构建链路;
- CCache 归档格式修正(Backported in #46509,原始 PR #46490,作者 Felixoid):CCache 压缩格式早已改为
zst,但 CI 默认下载仍是gz归档,该修复让下载优先选择 zst 归档,加速开发者二次编译; - 旧发行版/ARM 上 glibc 符号问题(Backported in #47058,原始 PR #47008,作者 rschu1ze):修复在 Amazon Linux 2 等旧 glibc(2.28)系统和 ARM 上启动服务器时报"找不到 glibc 2.28 符号"的错误。从仓库结构看,项目通过 contrib/glibc-compatibility 目录维护了针对新 glibc 符号的兼容层,这类"二进制在旧系统上运行"的问题正是该兼容机制需要覆盖的场景,建议旧系统/ARM 用户升级后验证启动行为;
- CI 镜像 ZooKeeper 下载修复(Backported in #45200,原始 PR #44853,作者 Felixoid):修复 CI 镜像中 ZooKeeper 的下载、更新版本并优化镜像体积,属测试基础设施改进。
维护性变更(不进入变更日志正文)
变更日志末尾的 "NOT FOR CHANGELOG / INSIGNIFICANT" 小节收录了不影响用户行为的流程性改动,主要围绕发布自动化:自动合并绿色 backport/已批准 PR(#41110)、改进发布脚本(#45074)、用 r2 + ch-repos-manager 替代 artifactory 托管包(#45421)、修复 automerge 的调试可观测性(#45476、#46080)、release workflow 的 GITHUB_TAG 处理(#45636)、sanitizer 依赖补全(#45959)、install_check.py与 aarch64 安装测试依赖修正(#46458、#46597)、以及"垂直合并写缓冲区析构顺序"这类内部修正(#46205,作者 KochetovNicolai)。其中垂直合并缓冲区析构顺序一项与上文性能小节同属 KochetovNicolai 的写入路径系列修复,二者可视为同一改进方向的配套。
升级建议小结
- 远端存储用户(S3 等):垂直合并内存修复 +
max_insert_delayed_streams_for_parallel_write生效 + LowCardinality 字典远端读修复,是本次补丁对远端部署最集中的价值,写入内存敏感的集群建议升级后关注 merge/insert 峰值内存; - 出现偶发段错误且涉及远端 DNS 的实例:c-ares 回调悬垂修复(#45629)是明确的根因级修复,值得作为升级依据;
- Replicated 表元数据读取报错的 Keeper 用户:EPHEMERAL 默认值修复(#44026)直接对应该症状;
- 单独部署 clickhouse-keeper 集群的用户:新增的 systemd 单元(#45568)让 keeper 具备了与 server 对等的服务化部署能力;
- 所有修复均为 backport,不引入新的行为特性,对 22.12 分支上的稳定版本而言是低风险、高收益的补丁升级。
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考