ClickHouse v25.7.6.21-stable 发布解读:按日志通道启用 JSON 输出与 8 项关键修复回移
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
本文基于 ClickHouse 仓库中 v25.7.6.21-stable 的 changelog(docs/changelogs/v25.7.6.21-stable.md),逐项解读该 LTS 补丁版相对 v25.7.5.34-stable 引入的 1 项功能增强与 8 项 Bug 修复,并结合当前仓库源码说明这些改动的落点。读完本文,你可以判断该版本是否值得升级到生产环境,并掌握按日志通道开启 JSON 日志的完整配置方式。
版本定位:面向 LTS 分支的回移发布
该 release 的基线信息为:
- 版本:v25.7.6.21-stable,构建提交
a81134c5c92; - 对比基线:v25.7.5.34-stable(
a031c88152d)。
所有条目均以 “Backported in #...” 开头,说明这些改动最初合入主干,随后回移(backport)到 25.7 LTS 分支。对生产环境意味着:如果你在 25.7 LTS 上运行 ClickHouse,升级到 25.7.6.21 即可获得下列修复,而不需要跨大版本迁移。changelog 标题中的 “FIXME as compared to ...” 是 changelog 自动生成脚本的占位标记,表示这是两个 stable 提交之间的差异清单,不是需要人工处理的错误。
增强:JSON 日志只输出到指定通道
本版本唯一的 Improvement 条目:新增“仅对特定日志通道启用 JSON 格式”的能力。做法是在日志格式配置节中增加logger.formatting.channel,取值为syslog、console、errorlog、log四者之一(对应 PR #86331,回移单 #86504)。
配置方式
ClickHouse 的日志输出由buildLoggers()拆分为多个通道:普通日志文件(log)、错误日志(errorlog)、syslog 与控制台(console)。在引入 channel 过滤之前,logger.formatting的 JSON 格式是全局生效的;现在可以通过channel子键将 JSON 格式绑定到单一通道,例如只让 errorlog 输出 JSON,其余通道保持人类可读的文本格式:
<logger> <level>warning</level> <console>1</console> <errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog> <errorlog_level>warning</errorlog_level> <formatting> <channel>errorlog</channel> <type>json</type> </formatting> </logger>其中type设为json是触发 JSON 输出的关键;channel省略时该格式配置对所有通道生效(作为全局回退)。
源码层面的实现
该能力的实现位于 src/Loggers/Loggers.cpp 的getFormatForChannel():
Poco::AutoPtr<OwnPatternFormatter> getFormatForChannel(Poco::Util::AbstractConfiguration & config, const std::string & channel, bool color) { Poco::Util::AbstractConfiguration::Keys keys; config.keys("logger", keys); std::string config_prefix_for_channel; std::string config_prefix_global; for (const auto & key : keys) { if (key != "formatting" && !key.starts_with("formatting[")) continue; if (config.getString(fmt::format("logger.{}.channel", key), "") == channel) { config_prefix_for_channel = "logger." + key; break; } ... } const auto & config_prefix = config_prefix_for_channel.empty() ? config_prefix_global : config_prefix_for_channel; if (config.getString(config_prefix + ".type", "") == "json") return new OwnJSONPatternFormatter(config, config_prefix); else return new OwnPatternFormatter(color); }从源码结构可以确认几个要点:
- 代码同时遍历
logger.formatting与索引形式的logger.formatting[0]、logger.formatting[1]等键(第 80 行的starts_with("formatting[")判断),因此可以定义多组格式配置,每组各自声明channel; - 匹配优先级为“通道精确匹配优先、未声明 channel 的格式配置作为全局回退”(第 88-95 行),这与上文 XML 示例的行为一致;
- 每个通道的格式化器由
getFormatForChannel(config, "log")之类的调用独立选择,如log通道在 Loggers.cpp 第 159-160 行 被构建为带格式器的OwnFormattingChannel。
这一改动的典型适用场景是:运维侧希望 errorlog 以 JSON 结构输出以便被日志采集器(解析为结构化字段),同时保留 console/普通日志为文本格式便于交互式排障,无需为不同通道拆分多个进程或配置文件。
Bug 修复(1):并行副本协作判定改用collaborate_with_initiator
changelog 条目(回移单 #86112):使用distributed_depth作为 *Cluster 函数的指示器是不正确的,可能导致数据重复(data duplication);应改用client_info.collaborate_with_initiator(PR #85734)。
该修复在源码中的落点清晰可见。src/Interpreters/ClientInfo.h 中同时存在两个字段:
UInt64 distributed_depth = 0; ... /// For parallel processing on replicas bool collaborate_with_initiator{false};distributed_depth记录查询经过 Distributed 转发的深度,它刻画的是“分布式查询嵌套层次”,与“该节点是否正在与发起副本协作并行处理”是两个不同语义——在多层转发、并行副本等组合场景下用它判断协作身份确实会误判;collaborate_with_initiator是专为并行副本处理引入的标志位(注释即 “For parallel processing on replicas”),默认false。
该标志的判定点位于 src/Interpreters/Context.cpp 第 8937-8942 行,任务型并行副本(task-based parallel replicas)的可用性与该标志取反/取直组合使用。标志的跨节点传递由ClientInfo::write/read序列化(见 src/Interpreters/ClientInfo.cpp 第 304 行写入、第 453 行读取),并有专门的序列化往返测试 src/Interpreters/tests/gtest_client_info_read.cpp 覆盖该字段的读回。
对用户的意义:此前依赖distributed_depth推断“我在集群查询的第几层”的自定义逻辑或旧版本行为,在涉及 Cluster 函数(如clusterAllReplicas、s3Cluster等按副本执行路径)时可能出现副本重复返回数据。升级到此版本后该判定改为显式标志,属于正确性修复,建议在多副本集群上重点验证。
Bug 修复(2):DatabaseReplicated下CREATE ... AS (SELECT * FROM s3Cluster(...))的逻辑错误
条目(回移单 #86266):在DatabaseReplicated环境中执行CREATE TABLE ... AS (SELECT * FROM s3Cluster(...))会触发逻辑错误,现已修复(PR #85904)。
这是“复制数据库 + 集群表函数”组合场景的修复:CREATE TABLE AS (SELECT ...)需要先在本地建表、再执行远程选择器把数据拉回来,而在DatabaseReplicated下建表动作本身还会在副本间同步,叠加s3Cluster这类集群化 S3 访问函数时,建表与数据读取的时序/身份判断出现了逻辑错误。如果你使用DatabaseReplicated做跨副本的湖仓外表批量导入,升级后可消除该路径上的报错。
Bug 修复(3):Unity Catalog 忽略非 Delta 表中的“怪异”数据类型 schema
条目(回移单 #86163,修复 issue #85699):Unity Catalog 在处理非 Delta 表时,现在会忽略带有不兼容(“weird”)数据类型的 schema(PR #85950)。
这属于容错性修复:此前遇到无法映射的数据类型时整个 schema 的处理可能被中断,现在对非 Delta 格式的表采取跳过策略,保证其余正常列可被读取。如果你通过 Unity Catalog 对接第三方 Iceberg 等湖表且偶发 schema 解析失败,此修复直接相关。
Bug 修复(4):index_granularity_bytes = 0时FINAL+ skip index 抛异常
条目(回移单 #86291):当表(例如ReplacingMergeTree)以index_granularity_bytes = 0创建时,带 skip index 的FINAL查询会抛出异常,现已修复(PR #86147)。
index_granularity_bytes是粒度控制的字节阈值形式,设为0属于合法的边界配置(表示不按字节阈值触发新标记块)。此前该边界值与 skip index 在FINAL查询中的索引扫描路径组合时未做防护,导致直接抛异常。如果你的历史表曾使用该设置,升级后此类FINAL查询可恢复正常执行。
其余 4 项崩溃/正确性修复
changelog 中还有 4 项均为高优先级的稳定性修复,逐条说明如下:
1. 同一次 INSERT 中混合常量块与非常量块导致崩溃(#86308)
changelog 原文(PR #86230,回移单 #86308):修复单次 INSERT 中同时出现 const 与 non-const 块时的崩溃。
这类场景常见于异步插入攒批、或客户端一次性提交多个结构不同的 block(部分列是常量、部分不是)时。修复前服务端在合并处理时假设块类型一致,触发崩溃。对高吞吐批量写入(尤其配合INSERT批量协议或Buffer表)的集群,这是典型的可用性修复。
2.ALTER UPDATE Nullable(JSON)导致崩溃(#86348)
changelog 原文(PR #86281,回移单 #86348):修复对Nullable(JSON)列执行 mutation(ALTER UPDATE)时的崩溃。
Nullable(JSON)与 JSON 列的 mutation 路径涉及对每个非 NULL 值的重新序列化,属于 JSON 列支持中较边缘但可触发的组合。如果你在 JSON 列上加了Nullable并计划做后台 mutation(ALTER TABLE ... UPDATE),建议先升级再操作。
3. 物化视图同名重建后不工作(#86454)
changelog 原文(PR #86413,回移单 #86454):物化视图若被创建、删除后再以相同名称重新创建,可能出现不工作的情况。已修复(作者 Alexander Tokmakov)。
这是 MV 生命周期管理中的状态残留问题:drop 后再 create 同名 MV 时,内部某项与名称关联的状态未被正确清理/重建,导致新 MV 数据管道不生效。对运维自动化脚本(先 drop 后 create 的幂等建表流程)尤为关键。
4.Buffer表引起MergesMutationsMemoryTracking泄漏,以及query_views_log在 Kafka 流式读取下不记录(#86466)
changelog 原文(PR #86422,回移单 #86466):
- 修复由
Buffer表引起的MergesMutationsMemoryTracking内存跟踪对象泄漏; - 修复从
Kafka等引擎流式读取(streaming)时system.query_views_log记录不正确的问题。
前者意味着长期运行的实例上,围绕 merge/mutation 的内存追踪会随Buffer表流量缓慢累积,属于典型的“慢泄漏”,升级后可恢复内存可观测性;后者让Kafka等流式源引擎的查询正确落进query_views_log,完善了基于该表的查询审计与 MV 血缘统计。
小结:这个补丁版解决了什么问题
v25.7.6.21-stable 相对 v25.7.5.34-stable 的变更可以归纳为三类价值:
| 类别 | 条目 | 面向场景 |
|---|---|---|
| 功能增强 | 按通道启用 JSON 日志(logger.formatting.channel) | 日志结构化采集,通道级格式控制 |
| 数据正确性 | collaborate_with_initiator替代distributed_depth判定 | 并行副本 / *Cluster 函数场景防数据重复 |
| 数据正确性 | DatabaseReplicated+s3ClusterCTAS 逻辑错误 | 复制数据库下集群湖表导入 |
| 数据正确性 | Unity Catalog 容错跳过非常规类型 schema | 湖仓表 schema 解析 |
| 数据正确性 | FINAL+ skip index +index_granularity_bytes = 0 | 边界粒度配置的 FINAL 查询 |
| 稳定性 | INSERT 混合 const/non-const 块崩溃、ALTER UPDATE Nullable(JSON)崩溃、MV 同名重建失效 | 写入路径、mutation、MV 生命周期 |
| 可观测性/内存 | MergesMutationsMemoryTracking泄漏、query_views_log流式源记录 | 内存追踪、查询审计 |
升级建议:由于本版本包含一个可能引发数据重复的并行副本正确性修复(distributed_depth判定),在多副本集群上使用clusterAllReplicas类函数的用户应优先升级;使用DatabaseReplicated、JSON 列、Buffer表或物化视图自动化流程的用户同样建议升级。所有修复均已回移到 25.7 LTS 分支,升级成本仅为补丁版本切换,无需跨主版本。
【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考