
ClickHouse v24.3.17.18-lts 变更解析从 JOIN 空值安全到 Docker 初始化与 DISTINCT 崩溃修复【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse导读本文以 ClickHouse 官方发布记录 docs/changelogs/archive/v24.3.17.18-lts.md 为主体逐一剖析该 LTS 补丁版本中的 4 个用户可见缺陷修复与 1 项构建/测试/打包改进。你会了解到LowCardinality 与空值安全 JOIN 的语义修复原理、DistinctSortedStreamTransform空指针解引用崩溃的成因、PostgreSQL 物化复制中未捕获异常导致的进程崩溃、以及docker-init与clickhouse extract-from-config --users在 Docker 入口脚本重构中的协同工作方式并掌握对应的源码位置与排查手段。版本概览v24.3.17.18-lts 修复了什么v24.3.17.18-lts构建哈希b163637e2f7是 ClickHouse 24.3 LTS 分支的一次补丁迭代基线为 v24.3.16.16-lts构建哈希1303dad1849。本次发布的变更分为三类类别数量内容Bug Fix用户可见的官方稳定版缺陷4LowCardinality 空值安全 JOIN、DistinctSortedStreamTransform空指针解引用、PSQL 复制未捕获异常崩溃、docker-init 失败日志Build/Testing/Packaging Improvement1将entrypoint.sh的服务器相关逻辑函数化并为extract-from-config新增--users开关NOT FOR CHANGELOG / INSIGNIFICANT2修复test_replicated_merge_tree_s3_zero_copy不稳定测试常规测试修复下文按用户影响从大到小的顺序展开。1. 修复 LowCardinality 下的空值安全 JOIN1.1 问题现象在 v24.3.16.16-lts 及更早版本中当 JOIN 的 ON 条件使用空值安全比较nullsafe comparison时若关联列为LowCardinality类型结果会出现错误。受影响的比较写法包括-- 方式一IS NOT DISTINCT FROM SELECT ... FROM a JOIN b ON a.k IS NOT DISTINCT FROM b.k -- 方式二宇宙飞船运算符 SELECT ... FROM a JOIN b ON a.k b.k -- 方式三手工展开的空值安全判定 SELECT ... FROM a JOIN b ON (a.k IS NULL AND b.k IS NULL OR a.k b.k)所谓空值安全比较是指 NULL 与 NULL 视为相等区别于普通在 SQL 三值逻辑下返回 NULL。IS NOT DISTINCT FROM、以及第三条手工写法都是这一语义的等价表达。1.2 根因分析修复 PR 将问题定位在 JOIN ON 条件的表达式分析阶段。当列被LowCardinality包装时其空值表示与普通可空列不同——LowCardinality(Nullable(T))的空值以字典索引的特殊形式存储。在进行空值安全比较的改写时执行器需要区分字典中值为 NULL 的条目与普通 NULL 值而旧实现未正确处理这一差异导致IS NOT DISTINCT FROM等改写无法在 LowCardinality 列上正确求值。从源码结构看该逻辑集中在 JOIN 条件改写相关的三个文件src/Interpreters/JoinExpressionActions.cpp生成 JOIN 两侧的表达式动作包括空值安全比较的改写src/Interpreters/CollectJoinOnKeysVisitor.cpp从 ON 条件中提取关联键src/Interpreters/TableJoin.cpp 与 src/Interpreters/TableJoin.h维护 JOIN 描述与键的类型信息。修复 PR#75143针对这些路径补上了对 LowCardinality 可空类型的显式处理。1.3 影响面与建议受影响的场景是JOIN 键声明为LowCardinality(Nullable(T))且 ON 条件使用空值安全比较。升级到 v24.3.17.18-lts 后无需任何配置变更即可获得正确结果若你正在使用上述三种写法中的任意一种建议升级后对相关查询做一次回归验证尤其是多列 JOIN 键混合可空/非可空类型的情形。2. 修复 DistinctSortedStreamTransform 空指针解引用2.1 问题现象在特定输入下DistinctSortedStreamTransform会发生空指针解引用null pointer dereference导致服务进程崩溃core dump。该问题属于用户可见的稳定版缺陷通过 #75830 跟踪。2.2 源码定位该变换类位于 src/Processors/Transforms/DistinctSortedStreamTransform.h 与 src/Processors/Transforms/DistinctSortedStreamTransform.cpp是SELECT DISTINCT在输入流已有序ORDER BY 与 DISTINCT 列一致时的优化实现。其核心思路见 DistinctSortedStreamTransform.h 的注释将 DISTINCT 列分为两组排序前缀列sorted与非排序列other按排序前缀值将行切分为区间range区间内若无非排序列直接保留首行、过滤其余行若存在非排序列则用哈希表ClearableSetVariants做区间内去重跨 chunk 边界时通过记录上一个 chunk 最后一行的排序键prev_chunk_latest_key判断当前 chunk 是否是上一 chunk 的延续从而正确处理有序流。该变换由查询计划中的 DISTINCT 步骤按需创建见 src/Processors/QueryPlan/DistinctStep.cpp。2.3 根因与修复崩溃点与跨 chunk 延续路径有关。transform()在处理每个 chunk 时调用continueWithPrevRange()其内部通过isLatestKeyFromPrevChunk()将上一 chunk 保存的键与当前 chunk 首行比较当输入块的列结构如列数、常量列表示在 chunk 间发生变化时旧实现对空列的访问缺少保护从而触发空指针解引用。修复 PR#75734为空指针路径补充了防御性判断。值得一提的是本文件 DistinctSortedStreamTransform.cpp 中保留的一段注释印证了该区域的历史敏感性temporary hardening due to suspious crashes in sqlancer tests即此前已因 SQLancer 模糊测试发现过同区域崩溃并加过防护本次是同类问题的再次加固。该变换另有配套测试 src/Processors/tests/gtest_distinct_sorted_stream_transform_limits.cpp 用于回归验证大小限制等行为。2.4 触发条件与建议该崩溃通常出现在有序 DISTINCT 处理路径上即SELECT DISTINCT配合ORDER BY或查询本身利用排序列前缀时且数据跨多个 block 分片。若你的生产环境曾出现DistinctSortedStreamTransform相关的 core dump升级本版本即可若为规避问题曾改写查询例如去掉 DISTINCT 或强制不同排序升级后可尝试恢复原查询形态。3. 修复 PostgreSQL 物化复制中的未捕获异常崩溃3.1 问题现象通过MaterializedPostgreSQL引擎物化 PostgreSQL 表或 PostgreSQL 数据库复制功能时若复制线程在特定错误路径上抛出异常而未被捕获会导致整个 ClickHouse 服务进程崩溃。该问题通过 #76227 跟踪。3.2 源码定位相关实现位于 src/Storages/PostgreSQL/PostgreSQLReplicationHandler.h 与 src/Storages/PostgreSQL/PostgreSQLReplicationHandler.cpp承载 PostgreSQL 的 WAL 复制处理逻辑表级入口为 src/Storages/PostgreSQL/StorageMaterializedPostgreSQL.cpp。从源码结构看复制处理涉及两类关键配置定义于MaterializedPostgreSQLSettings见 PostgreSQLReplicationHandler.cppmaterialized_postgresql_backoff_factor重试退避因子materialized_postgresql_backoff_max_ms退避最大毫秒数。3.3 修复方式修复 PR#75062在复制处理的异常边界上补捕获确保复制线程在遇到错误时进入受控的重试/退避流程而不是让异常逃逸到线程出口导致进程终止。这符合复制场景的预期行为连接中断、WAL 读取失败等错误应触发重试而非崩溃。3.4 影响面与建议影响对象使用MaterializedPostgreSQL表引擎或 PostgreSQL 复制功能的用户。若你在使用中观察到服务因复制异常意外退出日志中伴随 uncaught exception 字样升级本版本即可获得修复升级后建议观察system.processors_profile_log与复制相关的system.replication_queue类监控确认复制状态恢复。4. docker-init 失败日志改进与入口脚本函数化重构4.1 变更内容本版本将两项相关改动合入一是修复docker-init失败日志信息使其语义更清晰#71734二是将 docker/server/entrypoint.sh 中与 clickhouse-server 相关的全部操作封装为函数并仅当启动默认二进制时执行#75643。后者是一个长期搁置的改进最早由 #50724 提出建议。4.2 entrypoint.sh 的函数化结构重构后的 entrypoint.sh 将初始化逻辑拆分为三个函数函数职责对应源码位置manage_clickhouse_directories从配置中解析数据目录、临时目录、日志目录、用户文件目录、外部磁盘路径与文件系统缓存路径逐项建目录并必要时递归 chownentrypoint.shmanage_clickhouse_user比较原始users.default与处理后的用户配置决定是否创建自定义用户、锁定默认用户网络访问或保持不变entrypoint.shinit_clickhouse_db数据目录未初始化时以仅监听 localhost 的临时 server 执行/docker-entrypoint-initdb.d下的初始化脚本并创建CLICKHOUSE_DBentrypoint.sh这些函数仅在第一个参数为空或以--开头即启动默认 server 二进制时执行entrypoint.sh其余情况直接exec $透传给用户指定命令。这正是 changelog 所述仅当启动默认二进制时执行的含义也是通过 Docker 官方一致性测试library consistency test所要求的。4.3 新增 --users 开关从 users.xml 提取配置为了让入口脚本能够从用户配置文件而非主配置中读取用户信息本次为clickhouse extract-from-config新增了--users开关# 从主配置中读取用户目录配置再定位 users.xml clickhouse extract-from-config --config-file $CLICKHOUSE_CONFIG --keyuser_directories.users_xml.path # 使用 --users直接切换到 users.xml 视角提取键值 clickhouse extract-from-config --config-file $CLICKHOUSE_CONFIG --users --keyusers.default --try--users的实现位于 src/Common/Config/ConfigProcessor.cpp 的上层调用 programs/extract-from-config/ExtractFromConfig.cpp当get_users为真时程序先从主配置读取user_directories.users_xml.path相对路径则基于主配置文件所在目录解析再针对该 users.xml 重新加载配置并执行键提取ExtractFromConfig.cpp。其命令行参数完整定义如下ExtractFromConfig.cpp--help 显示帮助 --stacktrace 打印异常堆栈 --process-zk-includes 若配置含 from_zk 元素连接 ZooKeeper 处理 --try 缺失键/缺失用户配置/缺失 include_from 文件时不告警 --users 从 users.xml 配置中返回值本版本新增 --log-level level 日志级别默认 error --config-file, -c path 配置文件路径必填 --key, -k key 要提取的键必填入口脚本正是用它完成了检测默认用户是否被挂载的配置自定义的判断entrypoint.shORIGINAL_DEFAULT$(clickhouse extract-from-config --config-file $USERS_CONFIG --keyusers.default | sha256sum) PROCESSED_DEFAULT$(clickhouse extract-from-config --config-file $CLICKHOUSE_CONFIG --users --keyusers.default --try | sha256sum) [ $ORIGINAL_DEFAULT $PROCESSED_DEFAULT ] CLICKHOUSE_DEFAULT_CHANGED0 || CLICKHOUSE_DEFAULT_CHANGED1--users将原来需要手工定位 users.xml 的逻辑内聚到单一工具中同时支持--try静默处理缺失场景。4.4 docker-init无 Shell 环境的等价实现clickhouse docker-initprograms/docker-init/docker-init.cpp是 distroless 镜像无 bash、无 coreutils下的入口程序用 C 实现了 entrypoint.sh 的全部能力。本次失败日志改进即落在该文件目录创建、chown、临时 server 就绪等待等失败路径统一输出带docker-init:前缀、包含 errno/路径信息的明确日志例如 docker-init.cpp 的couldnt create directory ...便于在无 Shell 环境中快速定位问题。docker-init内部大量复用extract-from-config子命令完成配置提取docker-init.cpp且同样支持--users参数用于判断默认用户是否被外部挂载配置自定义docker-init.cpp# 用法 clickhouse docker-init [--keeper] [-- extra-server-args...]环境变量与 entrypoint.sh 完全一致包括CLICKHOUSE_CONFIG、CLICKHOUSE_RUN_AS_ROOT、CLICKHOUSE_DO_NOT_CHOWN、CLICKHOUSE_UID/GID、CLICKHOUSE_USER/PASSWORD、CLICKHOUSE_DB、CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT、CLICKHOUSE_SKIP_USER_SETUP、CLICKHOUSE_ALWAYS_RUN_INITDB_SCRIPTS、CLICKHOUSE_INIT_TIMEOUT等见 docker-init.cpp 的 --help 输出。Keeper 模式下则使用KEEPER_CONFIG、CLICKHOUSE_DATA_DIR、LOG_DIR。Docker 镜像的构建配置位于 docker/server其中 Dockerfile.distroless 即使用docker-init作为入口。5. 测试稳定性修复NOT FOR CHANGELOG本版本还包含两条未进入正式 changelog 的稳定性修复修复test_replicated_merge_tree_s3_zero_copy的 flaky 测试#73102通过减少循环次数与退避周期避免test_drop_table超过客户端超时。该测试位于 tests/integration 下用于验证 ReplicatedMergeTree 与 S3 零拷贝复制场景中删表行为的正确性常规测试修复#75675。这类改动不改变用户可见行为但对 CI 稳定性的贡献在于减少因超时导致的假失败使每次提交的测试信号更可信。升级建议与验证清单确认当前版本clickhouse-server --version应显示v24.3.17.18-lts或更高 LTS 补丁。回归重点一查询语义覆盖 LowCardinality 可空列上的IS NOT DISTINCT FROM、与手工空值安全 JOIN 写法回归重点二稳定性若此前出现过DistinctSortedStreamTransform崩溃或 PostgreSQL 复制异常退出升级后运行对应负载观察system.errors与 core dump 是否复现Docker 场景验证挂载自定义 users.xml、设置CLICKHOUSE_USER/PASSWORD、/docker-entrypoint-initdb.d初始化脚本在 Ubuntu 与 distroless 镜像下均按预期工作工具链可在宿主机直接验证新开关的行为例如对标准配置执行clickhouse extract-from-config --config-file /etc/clickhouse-server/config.xml --users --keyusers.default --try。参考源码索引发布记录 docs/changelogs/archive/v24.3.17.18-lts.mdJOIN 空值安全改写 src/Interpreters/JoinExpressionActions.cpp、src/Interpreters/CollectJoinOnKeysVisitor.cpp、src/Interpreters/TableJoin.cppDISTINCT 有序变换 src/Processors/Transforms/DistinctSortedStreamTransform.cpp、src/Processors/QueryPlan/DistinctStep.cpp、src/Processors/tests/gtest_distinct_sorted_stream_transform_limits.cppPostgreSQL 复制 src/Storages/PostgreSQL/PostgreSQLReplicationHandler.cpp、src/Storages/PostgreSQL/StorageMaterializedPostgreSQL.cppDocker 入口与配置提取 docker/server/entrypoint.sh、programs/docker-init/docker-init.cpp、programs/extract-from-config/ExtractFromConfig.cpp、docker/server/Dockerfile.distroless【免费下载链接】ClickHouseClickHouse® is a real-time analytics database management system项目地址: https://gitcode.com/GitHub_Trending/cli/ClickHouse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考