ClickHouse v24.8.7.41-lts 更新解析:Docker 加固、特权降级修复与 12 项稳定性 Bug Fix
2026/9/20 10:02:12 网站建设 项目流程

ClickHouse v24.8.7.41-lts 更新解析:Docker 加固、特权降级修复与 12 项稳定性 Bug Fix

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

本指南以 ClickHouse 官方仓库 v24.8.7.41-lts 变更日志 为骨架,逐条拆解该 LTS 补丁版本中的 3 项改进、12 项用户可见 Bug 修复与构建/打包优化,并结合仓库源码(docker/server/entrypoint.shprograms/su/su.cppsrc/Common/HostResolvePool.cppsrc/Functions/bitShiftLeft.cpp等)讲解每项变更的底层原理。读完本文,你将理解 24.8 LTS 分支在 Docker 镜像安全、进程权限降级、DNS 解析负载均衡、JSON/Variant 数据类型、分析器与旧分析器兼容等方向上的演进脉络,并能据此评估升级影响、复现修复场景或验证特定行为。

版本背景与发布范围

v24.8.7.41-lts(git 提交e28553d4f2b)是 24.8 长期支持(LTS)分支的又一个补丁版本,基线对比对象为 v24.8.6.70-lts(ddb8c219771)。从变更日志结构看,本次发布包含:

  • 3 项改进(Improvement):Docker 镜像中CLICKHOUSE_PASSWORD的 XML 转义、clickhouse su对数值型UID:GID的支持、HostResolver解析频率调整;
  • 12 项 Bug Fix:涵盖 HTTP 压缩响应、命名集合(named collections)、JSON 类型推断、Variant 列、优化器规则、分析器、UDF 约束、位位移函数、ALTER 空元组、分区列谓词、客户端语法高亮等;
  • 1 项构建/测试/打包改进Dockerfile.ubuntu重构与环境变量治理;
  • 2 项内部(NOT FOR CHANGELOG)变更:backport 流程与官方镜像同步。

所有修复均以 backport(cherry-pick 回移植)方式合入 24.8 分支,每个条目对应的原始 PR 与追踪 issue 号已在日志中列出。

Improvement 一:Docker 镜像密码的 XML 转义加固

变更内容

PR #69301(backport #71713)修复了 clickhouse 镜像 entrypoint 中CLICKHOUSE_PASSWORD未进行 XML 转义的问题。

在旧行为下,若用户通过环境变量传入的密码包含&<>"'等 XML 特殊字符,生成到/etc/clickhouse-server/users.d/default-user.xml的密码内容会被 XML 解析器误读,导致配置非法或密码解析错误。

源码佐证

在 docker/server/entrypoint.sh 的manage_clickhouse_user函数中,密码被写入用户配置文件时使用了<![CDATA[...]]>包裹:

cat <<EOT > /etc/clickhouse-server/users.d/default-user.xml <clickhouse> <users> <default remove="remove"> </default> <${CLICKHOUSE_USER}> <profile>default</profile> <networks> <ip>::/0</ip> </networks> <password><![CDATA[${CLICKHOUSE_PASSWORD//]]>/]]]]><![CDATA[>}]]></password> <quota>default</quota> <access_management>${CLICKHOUSE_ACCESS_MANAGEMENT}</access_management> </${CLICKHOUSE_USER}> </users> </clickhouse> EOT

其中${CLICKHOUSE_PASSWORD//]]>/]]]]><![CDATA[>}是 bash 的字符串替换技巧:把密码中出现的]]>替换为]]]]><[![CDATA[>,从而在 CDATA 段内安全地嵌套该序列。这保证了任何密码字符(包括 XML 保留字符)都能被正确解析,避免因密码含特殊字符而导致服务无法启动或用户认证异常。

使用说明

在 Docker 中通过CLICKHOUSE_PASSWORD设置密码时(参见 entrypoint.sh](https://gitcode.com/GitHub_Trending/cli/ClickHouse?utm_source=gitcode_repo_files),密码同样支持通过CLICKHOUSE_PASSWORD_FILE从文件读取),现在可以放心包含&<>、引号等字符。密码会在/etc/clickhouse-server/users.d/default-user.xml中正确生成,服务器可正常启动。

Improvement 二:clickhouse su支持数值型 UID:GID

变更内容

PR #71626(backport #71666)修复了当用户/组以数值 ID 形式给出时clickhouse su失败的问题,使其同时接受用户:组的字符串名和UID:GID数值形式。

源码佐证

programs/su/su.cpp 注释中说明了这个工具的设计动机:标准 Linuxsu因创建伪终端(pty)与 Docker 终端处理不兼容,因此 ClickHouse 提供自有的轻量su(即 "set user"),仅需两三个系统调用即可完成身份切换。

关键的setUserAndGroup函数(su.cpp)展示了修复后的解析逻辑:

bool parsed_numeric = tryParse(gid, arg_gid); if (!parsed_numeric || gid == 0) { group entry{}; group * result{}; if (0 != getgrnam_r(arg_gid.data(), &entry, buf.get(), buf_size, &result)) throw ErrnoException(...); if (!result) { /// 仅当输入确实解析为数字时才回退到按 gid 查询, /// 避免把拼写错误的组名静默解析成 root 组(gid 0) if (parsed_numeric && 0 != getgrgid_r(gid, &entry, buf.get(), buf_size, &result)) throw ErrnoException(...); if (!result) throw Exception(ErrorCodes::BAD_ARGUMENTS, "Group {} is not found in the system", arg_gid); } gid = entry.gr_gid; }

对 UID 的解析同理(su.cpp)。此外该实现还包含多处安全细节:

  • 先解析 GID 再降权:在仍有特权时完成initgroups()(重置补充组列表),避免降权后进程静默继承调用者(通常是 root)的补充组;
  • 数值 UID 但无 passwd 条目时清空补充组:调用setgroups(0, nullptr)而非错误地继承;
  • 防御性检查uid == 0 && getuid() != 0时抛出BAD_ARGUMENTS,防止把非 root 进程错误地"降到" root(su.cpp);
  • WASM 兼容:为 Emscripten 提供initgroups桩(返回ENOSYS,fail-closed),见 su.cpp。

使用说明

clickhouse su的用法为clickhouse su user[:group] args...,user 和 group 既可以是字符串名也可以是数值。修复前clickhouse su "101:102" cmd这类调用会失败,修复后可正常解析。Docker entrypoint 内部大量使用它来降权执行mkdir、启动clickhouse-server等操作(如 entrypoint.sh 中的mkdir=( clickhouse su "${USER}:${GROUP}" mkdir )),因此该修复直接影响 Docker 镜像在--user与 NFS 挂载等场景下的目录创建与权限管理。

Improvement 三:HostResolver 解析频率与 DNS 负载均衡

变更内容

PR #71863(backport #71936)将HostResolver在一个history周期内的解析次数更新为 3 次。

源码佐证

HostResolver是 ClickHouse 的多地址主机解析/连接池组件,实现在 src/Common/HostResolvePool.h 与 src/Common/HostResolvePool.cpp。头文件注释(HostResolvePool.h)概括了其四大特性:

  • 地址负载均衡selectBest()按权重随机选择地址,使用越多的地址权重越低,新地址会获得更高权重;
  • 解析结果合并:当主机被解析为不同地址集合时,合并所有地址并共同使用,地址在history_时间后过期;
  • 失败地址惩罚(pessimization)setFail()标记故障地址,该地址在history_时间内不再被选中(除非它重新出现在解析结果中或所有其他地址都被惩罚);
  • 解析调度:通过DB::DNSResolver::instance()解析,默认在history_周期内不超过 3 次,且每次setFail()都会触发一次新的解析。

默认历史窗口由DEFAULT_RESOLVE_TIME_HISTORY_SECONDS = 2*60(秒)定义(HostResolvePool.h)。构造函数中resolve_interval(history_.totalMicroseconds() / 3)(HostResolvePool.cpp)把解析间隔设为历史窗口的三分之一——这正是"3 次解析"的代码实现:一个 120 秒的窗口内,每 40 秒允许一次新解析。isUpdateNeeded()检查last_resolve_time + resolve_interval < now || records.empty()决定是否触发update()(HostResolvePool.cpp)。

权重策略见Record::getWeight()(HostResolvePool.h):使用量>10000权重为 1、>1000权重为 5、>100权重为 8、否则为 10。selectBest()在总权重为 0(全部地址被禁)时退化为均匀随机选择,避免partition_point越界(HostResolvePool.cpp)。相关测试见 src/Common/tests/gtest_resolve_pool.cpp 与 src/Common/tests/gtest_connection_pool.cpp。

影响分析

该改动提升了多 IP 后端(典型如集群中的分布式表远端节点、remote/cluster表函数)的解析新鲜度:每 40 秒即可发现 DNS 变更,同时仍保留 120 秒的历史合并窗口,兼顾了负载均衡的稳定性与故障转移的及时性。

Bug Fix 详解(12 项)

1. 部分压缩响应缺失Content-Encoding

PR #68975(修复 issue #64802,backport #71486)修复了某些压缩响应未发送Content-Encoding响应头的问题。该问题会影响 HTTP 接口下依赖响应头判断解压方式的客户端(如http_native_compression场景与各类 HTTP 驱动),缺失头会导致客户端按未压缩数据解析已压缩的响应体。修复后,只要响应体实际经过了压缩编码,就会正确携带Content-Encoding

2. 命名集合(Named Collections)缺少反转义导致服务无法启动

PR #71308(backport #71462)修复了命名集合中缺失的反转义处理——在修复前,若命名集合配置中含转义序列,clickhouse-server可能无法启动。

命名集合(CREATE NAMED COLLECTION/system.named_collections)用于集中管理外部数据源(如s3kafkaurlmysqlpostgresql等表函数与字典)的连接参数。XML 配置文件中的&amp;&#39;等实体在解析后需要正确还原为原始字符,否则传给底层连接器的 URL、密钥等参数会包含字面量&amp;等错误内容,进而导致启动或建表失败。此修复确保命名集合中的转义内容被正确反解析后使用。

3. JSON 类型提示中检查可疑与实验类型

PR #71369(backport #71747)在 JSON 类型的类型提示(type hints)解析中加入了可疑(suspicious)与实验(experimental)类型的检查。

自 24.x 起JSON数据类型支持用JSON(max_dynamic_paths=N, some.path.type_hint)语法声明路径类型。此前用户若在类型提示中写入如Object('json')等可疑/实验类型,可能被静默接受并在运行时产生意外行为;修复后这类类型会被显式拒绝或按规则处理,从源头避免类型混乱。

4. 修复 Variant 列 Chunk 中"Invalid number of rows"错误

PR #71388(backport #71604)修复了带Variant列时出现Invalid number of rows in Chunk错误的问题。

Variant(T1, T2, ...)是 ClickHouse 存储异构类型值的数据类型,内部由多个子列与判别信息组成。此前的实现中,某些操作(如部分列投影或动态子列裁剪)会导致 Variant 子列与主 Chunk 的行数不一致,从而触发Invalid number of rows in ChunkLOGICAL_ERROR。修复后 Variant 列的行数同步逻辑正确,涉及 Variant 列的查询不再报错。

5.optimize_rewrite_array_exists_to_has崩溃修复

PR #71432(backport #71826)修复了开启optimize_rewrite_array_exists_to_has时的崩溃。

该优化器规则位于 src/Analyzer/Passes/ArrayExistsToHasPass.cpp,作用是把arrayExists(x -> predicate, arr)这类表达式重写为更高效的has(arr, value)形式。从源码可见(ArrayExistsToHasPass.cpp),规则受设置optimize_rewrite_array_exists_to_has(在 src/Core/Settings.cpp 中注册)控制。修复前在特定谓词形态(如 lambda 中引用多个数组列)下重写会产生无效 AST,进而崩溃;修复后重写逻辑更稳健。

6. 旧分析器:arrayJoin出现在 WHERE 中的常量参数错误

PR #71476(backport #71517)修复了旧分析器(old analyzer)下,当arrayJoin可能出现在WHERE条件中时抛出Argument for function must be constant错误的回归。该问题是 PR #65414 引入的回归,修复确保旧分析器路径下arrayJoin的正确处理。

7. 旧分析器:SortCursor 0 列崩溃防护

PR #71494(backport #71551)在旧分析器路径下为SortCursor增加 0 列保护,防止特定查询形态(如ORDER BY无有效排序列的边界情况)导致排序游标崩溃。

8. 物化视图内 IN + CTE 查询的分析器修复

PR #71538(修复 issue #65598,backport #71614)修复了物化视图(materialized view)内部查询使用IN子句配合 CTE(WITH ... AS)时分析器报错或结果错误的问题,使物化视图内的 CTE 引用与外部查询保持一致的分析语义。

9. 约束(Constraint)中使用 UDF 的崩溃防护

PR #71541(backport #71566)避免在表约束(CONSTRAINT ... CHECK ...)中使用用户自定义函数(UDF)时发生崩溃。此前约束表达式对 UDF 的处理路径存在缺陷,特定输入下会触发段错误;修复后约束中的 UDF 调用被安全处理。

10. bitShift 函数越界行为改为返回 0 / 默认字符

PR #71580(backport #71727)将bitShiftLeft/bitShiftRight在移位越界时的行为从抛错改为返回 0(数值类型)或默认字符(字符串类型)。

源码佐证

以 src/Functions/bitShiftLeft.cpp 为例,修复后整数路径的越界判断为:

else if (static_cast<UInt256>(b) >= 8 * sizeof(A)) return static_cast<Result>(0);

即当移位位数b大于等于类型的位宽时,直接返回 0,不再抛ARGUMENT_OUT_OF_BOUND。字符串与 FixedString 路径同理:越界时分别插入默认值(空输出/填充 0 字节),见 bitShiftLeft.cpp 与 bitShiftLeft.cpp。负数移位仍然抛错(The number of shift positions needs to be a non-negative value),第二参数为 big integer 时仍抛NOT_IMPLEMENTED

-- 修复前:bitShiftLeft(1, 64) 抛错;修复后:返回 0 SELECT bitShiftLeft(toUInt64(1), 64); -- 0 SELECT bitShiftLeft('abc', 100); -- 空字符串(越界插入默认值)
行为一致性说明

bitShiftRight(src/Functions/bitShiftRight.cpp)遵循相同的语义修正。这一改变让位移函数在边界输入下返回类型默认值,与多数 SQL 方言的位移语义保持一致,消除了查询因边界输入而整体失败的风险。

11. ALTER 空元组导致 LOGICAL_ERROR

PR #71679(修复 issue #71647,backport #71876)修复了使用空元组执行ALTER操作时触发LOGICAL_ERROR的问题。例如ALTER TABLE t UPDATE c = tuple() WHERE ...或涉及空元组的表达式在 ALTER 更新/物化列路径中的处理此前存在缺陷,现已被正确解析。

12. 分区列谓词中 NOT IN 的常量集合转换修正

PR #71695(backport #71737)修复了在NOT IN操作符下对分区列谓词错误转换常量集合的问题。分区裁剪(partition pruning)逻辑此前会把col NOT IN (...)中的集合当作IN语义转换,导致裁剪结果错误(可能漏掉应扫描的分区或误裁剪);修复后NOT IN的分区谓词不被错误变换,裁剪正确性得到保证。

附带修复:clickhouse-client 语法高亮崩溃

PR #71949 目录下客户端前端代码。

Build/Testing/Packaging:Dockerfile.ubuntu 重构与环境变量治理

PR #71573 进行了系统化改进:

  • 弃用CLICKHOUSE_UID/CLICKHOUSE_GID环境变量:镜像改为更可预测的身份管理方式。在 docker/server/entrypoint.sh 中仍保留了向后兼容的读取逻辑(USER="${CLICKHOUSE_UID:-...}"),但官方已建议不再依赖该变量;
  • 移除CLICKHOUSE_DOCKER_RESTART_ON_EXIT处理:以符合容器规范与安全要求;
  • 统一二进制执行方式clickhouse-serverclickhouse-keeper以一致的方式启动,不再出现一处直接执行可执行文件、另一处执行/usr/bin/clickhouse*的不一致情况(见 entrypoint.sh 的exec clickhouse su "${USER}:${GROUP}" clickhouse-server ...模式)。

相关演进同步于 docker/server/Dockerfile、docker/server/Dockerfile.alpine、docker/server/Dockerfile.distroless 以及 docker/keeper 镜像体系。若你在生产环境使用 Ubuntu 基础镜像部署,升级后应关注:自定义 entrypoint 若引用了被移除/弃用的环境变量,需要改用新方案;容器内目录创建与权限管理由clickhouse su统一负责,NFS 等root==nobody场景下的行为保持不变(见 entrypoint.sh 的DO_CHOWN=0分支)。

NOT FOR CHANGELOG:内部流程修复

两条内部变更不面向用户,但对发布流程有意义:

  1. PR #71782(backport #71801):修复孤儿 backport 分支与已关闭发布 PR 上 fake-master 事件被发送到检查数据库的问题;
  2. PR #71825(backport #71836):将已在 docker-library/official-images#17876 应用的改动同步回每个分支,以确保各分支都有正确的Dockerfile.ubuntu

升级与验证建议

  • 备份与灰度:24.8 LTS 分支的补丁版本均保持向后兼容,升级前建议在测试环境回归涉及JSON/Variant 类型、named collections、bitShift 函数、物化视图+CTE、分区裁剪的查询;
  • 重点回归 SQL 示例
-- bitShift 越界新行为 SELECT bitShiftLeft(toUInt8(1), 8); -- 0(旧版本抛错) SELECT bitShiftLeft(toUInt64(1), 64); -- 0 -- JSON 类型提示实验类型检查 CREATE TABLE t (j JSON(max_dynamic_paths=4, 'a.b' UInt32)) ENGINE = MergeTree ORDER BY tuple(); -- 分区列 NOT IN 裁剪 SELECT count() FROM partitioned_table WHERE p NOT IN (1, 2);
  • Docker 用户:升级镜像后确认CLICKHOUSE_PASSWORD含特殊字符时服务正常启动;如自定义过 entrypoint,检查是否依赖CLICKHOUSE_UID/CLICKHOUSE_GIDCLICKHOUSE_DOCKER_RESTART_ON_EXIT
  • 验证工具:使用clickhouse su "0:0" idclickhouse su "1000:1000" id验证数值 UID:GID 支持。

总结

v24.8.7.41-lts 是一个典型的 LTS 稳定性补丁版本:它没有引入新特性,但通过 12 项用户可见修复与 3 项改进,系统性消除了 Docker 部署(密码转义、su数值 ID、Ubuntu 镜像治理)、连接层(HostResolver 解析频率、压缩响应头)、类型系统(JSON 提示、Variant 行数)与查询正确性(分析器、优化器、分区裁剪、bitShift 边界)等方向上的已知缺陷。对于 24.8 LTS 用户,该版本值得尽快跟进,以在保持 API 稳定的前提下获得更安全的容器部署体验与更可靠的查询行为。完整条目清单与 backport 关系见 v24.8.7.41-lts 变更日志。

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

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

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

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

立即咨询