datainfra前沿动态 · Vol.85

Iceberg Go 0.7.0 把扫描规划交给服务端目录;Druid 38 移除 ZooKeeper 任务运行器、把裁剪做进实时段;AWS 让索引与导出只覆盖你要的那一段;ClickHouse 四条分支在同一天各发一个补丁版

本期聚焦 10 月 1 至 3 日的四件事:iceberg-go 用约 750 个 PR 补齐 Iceberg V3 的几何类型、变体切分、删除向量与行血缘,并把扫描规划做成可委托给 REST 目录的选项;Apache Druid 38.0.0 把 Java 25 设为推荐、移除 ZooKeeper 任务运行器、让实时段也能按维度值裁剪;AWS 两天内给 Aurora DSQL 加部分索引、给 DynamoDB 导出加过滤与投影;ClickHouse 在 10 月 3 日四小时内给四条分支各打了一个补丁标签。

DataInfra Apache Iceberg iceberg-go Iceberg V3 REST Catalog Apache Druid Java 25 Amazon Aurora DSQL Amazon DynamoDB ClickHouse 补丁分支 索引下推 Lakehouse

10 月 1 日到 3 日这三天,四件事指向同一个动作:把「哪些数据要参与这次计算」的判断尽量往前挪,挪到离存储更近、离网络更近的一侧,并把不再打算支持的旧路径明确划掉。iceberg-go 0.7.0 一边补齐 Iceberg V3,一边把扫描规划做成可以委托给 REST 目录的选项——目录不再只回答「表在哪」,还能代你算出「该读哪些文件」。Druid 38.0.0 一边把 Java 17 与 ZooKeeper 任务运行器请出支持范围,一边把此前只在批处理段上生效的裁剪推进到实时段。AWS 在两天里给出两条体量不大但方向一致的公告:Aurora DSQL 支持部分索引,DynamoDB 导出支持过滤与投影,两者都是在数据被写出之前先筛掉不需要的部分。ClickHouse 则在 10 月 3 日的四个小时内给四条分支各打了一个补丁标签,把「升级」从按季度做的决策变成一条要被自动化接住的流。前三条都附了一份写清楚的代价清单。


iceberg-go 0.7.0:V3 补齐,扫描规划可以交给目录

事件概述

10 月 1 日,Apache Iceberg 社区发布 iceberg-go 0.7.0。这是 0.6.0(2026 年 5 月)之后约四个月的累积,合并了接近 750 个 PR,来自 53 位贡献者,其中 33 位是首次提交。iceberg-go 是 Iceberg 表格式的原生 Go 实现,面向需要在 Go 应用里直接读写和管理 Iceberg 表的场景——数据平台控制面、自研引擎、CLI 工具、以及越来越多用 Go 写的摄取与调度组件。

这个版本最有分量的一条不是某个类型或某个格式的支持,而是一项能力边界的变化:扫描规划(scan planning)可以委托给支持 scan-planning 端点的 REST 目录。本地规划仍是默认,远端规划需要显式开启。放在本期另一条线索旁边看会更清楚——Iceberg 社区刚在 10 月 1 日通过 read restrictions 规范,把治理策略的评估与执行权交给可信引擎;iceberg-go 这次做的是同一条路上的另一半:客户端把「读哪些文件」这件事也交出去。

技术解析

  • V3 几何与地理类型:geometry 与 geography 类型打通了 schema 层,支持 WKB 编码与 GeoArrow 转换、PROJJSON CRS 的读写、manifest 数据文件里emit geo bounds 并在 manifest 级别聚合,以及基于 bounding-box 的谓词做地理裁剪。
  • 变体切分(variant shredding):新增 shredded variant reader 与一个需要主动开启的 shredded variant writer,配套类型一致性推断、shredded 字段的 bounds、以及通过一个新增的 extract 表达式在 shredded 字段上做谓词下推。底层是 Arrow Go v18.8 的 compute.VariantGet kernel,字段被切分到查询所用类型时走零拷贝快路径。
  • 删除向量(deletion vectors):扫描端的 DV 读路径接通,DV 写入接进 position-delete producer,支持分区 V3 表的 DV,重复 merge-on-read 删除时会合并 DV;规划期的校验与 Java 的 DeleteFileIndex 对齐,并补了跨客户端的 DV 格式一致性测试。
  • 行血缘(row lineage):copy-on-write 重写时保留行血缘;V3 表里 V1/V2 时代生成的 manifest 会继承 first_row_id;在血缘跟踪正确的前提下,row-group 裁剪重新启用。
  • 元数据表与增量扫描:Table.Inspect 拿到一整套元数据表(history、snapshots、metadata_log_entries、refs、manifests、data_files、delete_files、entries、partitions、position_deletes、files、all_files、all_data_files、all_delete_files、all_manifests、all_entries)。扫描侧新增 NewIncrementalAppendScan(规划两个快照之间新增的数据文件)与 NewIncrementalChangelogScan(产出文件级 insert/delete 任务,并为行级 changelog 铺路)。
  • REST 服务端扫描规划:客户端侧有 scan-planning 方法、一个 WaitForPlan 轮询器,以及把 REST scan task 解码成 FileScanTask 的逻辑;委托侧支持远端任务的并发拉取,并配了重试、遥测与文档。正确性靠两套东西兜住——一套 Java scan-planning 集成测试,以及「远端规划产出的任务与本地规划等价」的验证。
  • 指标上报:新增 metrics 包,定义 Reporter 契约,扫描规划发出 ScanReport、提交发出 CommitReport(含环境上下文),内置 REST reporter 与 OpenTelemetry reporter,可通过 catalog、table、scan 三个层级选择 reporter。
  • 加密地基:引入 EncryptionManager 与 KeyManagementClient 接口与一个内存 KMS,KMS 通过 encryption.kms-type / encryption.kms-impl 注册表选择;提交时同步表元数据,锁重试行为与 Java 对齐;另有一套跨所有 catalog 实现运行的共享一致性测试。
  • 文件 IO 拆分:io/gocloud 拆成按云划分的后端包,应用只链接自己用到的云 SDK。Azure 支持 ManagedIdentityCredential;S3 新增连接超时配置、兼容 GCS HMAC 端点、允许显式 s3.* 凭据覆盖上下文里的 AWS 配置;Glue catalog 的 CLI 配置支持 aws-profile。
  • 性能:120 多个性能 PR 覆盖读写与规划路径。大 Parquet 文件按 row-group 字节范围拆成多个 scan task(由 read.split.target-size 控制);manifest 在多次扫描间缓存,编译后的 filter 与裁剪计划缓存,manifest 读取时做列投影,本地规划遵守 row limit;equality delete 按分区与 sequence number 建索引,position delete 按路径与分区建索引,按 scan task 惰性加载,并按 data-file metrics 裁剪 equality delete;过期快照与孤儿清理期间去重共享 manifest 读取;Parquet 字典编码默认开启,与 Java Iceberg 一致。
  • 近 400 个缺陷修复里几条值得一提:data-file 重写导致 DV 变成孤儿、OCC rewrite 复活、扫描丢行时 _row_id 重编号、截断字符串分区上 NOT STARTS WITH 的裁剪错误、字符串按 UTF-8 字节而非 Unicode 码点截断、大端对齐崩溃。
  • 破坏性变更:拼错的 WitMaxConcurrency 改成 WithScanMaxConcurrency;Transform 接口新增类型感知的 ToHumanStrType,外部实现必须补上,ToHumanStr(any) 进入弃用;catalog/hadoop 里的 MkdirIO 与 ReadDirIO 被移除,换成 MkdirAll 与 WalkDir;catalog/hadoop 不再把云 scheme 的注册当成副作用,用云存储的应用需要 blank-import 对应的 io 后端包;孤儿文件清理要求表的 FileIO 实现 ListableIO。

行业影响

Iceberg 的 REST Catalog 这两年一路从「提供元数据」往「参与执行」走。read restrictions 把治理策略的执行权委托给引擎,scan planning 把读路径的规划权委托给目录——两者合起来,目录正在变成一个可以被信任的计算参与者,而不只是一张表的注册表。对引擎作者来说这是好事:原本每个客户端都要自己实现一遍 manifest 裁剪、DV 处理、血缘跟踪,现在可以在「自己算」和「让目录算」之间选。

代价也写得很清楚。其一,远端规划目前是 opt-in,默认还是本地规划;其二,variant 列改用规范扩展名 arrow.parquet.variant 之后,0.7.0 能读新旧两个名字,但滚动升级期间旧版 iceberg-go 读不出新名字——混合版本并行的时间窗要自己压短;其三,catalog/hadoop 的云 scheme 不再自动注册,依赖这个副作用的代码在升级后会在运行期才炸。这些都是「升级当下看起来健康」型的问题,值得在发布清单里单独列一行。

相关链接


Druid 38.0.0:Java 17 与 ZooKeeper 任务运行器出局,裁剪进到实时段

事件概述

10 月 1 日,Apache Druid 发布 38.0.0,距 37.0.0(2026 年 5 月)约五个月,包含 250 多项新特性、缺陷修复、性能增强、文档改进与测试补充,来自 37 位贡献者。

大版本通常有两种做法:一种以新能力为主,一种以清账为主。38.0.0 属于后者偏多,但清得相当彻底——运行环境上把 Java 17 移出支持范围并推荐 Java 25;架构上把从 25.0.0 起就只是备选的 ZooKeeper 任务运行器直接删除;能力上则做了一件过去做不到的事:让实时段在查询时也能被裁剪,而不必等 compaction。三件事合起来,是一次「先划掉旧的,再把新的边界往外推一圈」的发布。

技术解析

  • Java:支持 Java 25,Java 21 继续支持,Java 17 不再支持。启动脚本在走 bin/run-java 时会读取 DRUID_JAVA_HOME/JAVA_HOME,否则回落到 PATH 上的 java。MiddleManager 现在也会遵守 JAVA_HOME。
  • ZooKeeper 任务运行器移除:druid.indexer.runner.type=remote(基于 ZooKeeper 的 RemoteTaskRunner)被删除。HTTP 的 httpRemote 自 25.0.0 起是默认,现在是唯一受支持的分布式任务运行器;local(进程内)仍保留用于单机测试,Kubernetes 扩展的 k8s 运行器不受影响。配置里还写着 remote 的话启动会失败。一并失效的配置项有七个:druid.indexer.runner.maxZnodeBytes、taskShutdownLinkTimeout、compressZnodes,以及 druid.zk.paths.indexer 下的 base、announcementsPath、tasksPath、statusPath。ZooKeeper 本身仍用于 Coordinator/Overlord 选主以及服务节点的宣告与发现。
  • Historical tier 别名:新增 Coordinator 动态配置 historicalTierAliases,可以把一个虚拟 tier 名映射到多个真实 Historical tier。加载/丢弃规则引用别名时,Coordinator 会展开成实际 tier——把 hot_1 与 hot_2 映射到 hot 之后,规则 {"hot": 2} 会在两个 tier 上各放 2 副本。一个真实 tier 只能归属一个别名。
  • 实时段查询模式:realtimeSegmentsOnly 弃用,换成 realtimeSegmentsMode,取值 include(默认,查所有段)、exclude(跳过实时段)、exclusive(只查实时段)。官方给的场景是蓝绿部署:只想查新的 Historical 自动伸缩组,不碰任何「活着的」节点。
  • 更快的段元数据检索:druid.segment.timeline.fastIntervalSearch 打开后用区间树索引在内存里存段元数据,加速定位与检索,默认关闭。
  • MSQ 后台取文件:MSQ 任务引擎的 worker 现在支持异步从云存储拉取输入文件,把下载与处理重叠起来,读大量文件时吞吐更好;否则 worker 一直是边处理边流式读。默认开启,由 backgroundFetchExternalFiles 控制。Dart 侧新增 druid.msq.dart.worker.segmentLoadAheadCount 控制段预取数量。
  • 可裁剪的流式段 shard spec:Kafka 摄取现在可以发布带 dim_value_set 的段——每个任务记录自己在若干低到中等基数维度上见到的不同值,并盖到段上;Broker 在查询时对声明过的维度做过滤,跳过取值集合不可能命中的段,不等 compaction。这个特性 opt-in、仅 Kafka、默认关闭。dim_value_set 是新的核心 shard spec 类型且没有 fallback,不向前兼容:必须先升级所有服务再开启;一旦发布过 dim_value_set 段,降级不被支持,直到这些段被 compaction 掉或配置被移除。另有可选的 maxValuesPerDimension。
  • supervisor 重启粒度:supervisor 不再对所有变更都重启。按变更类型分三档——只持久化更新后的 spec 不重启;重启 supervisor 但不影响运行中的任务;重启 supervisor 并终止任务(这是改动前的行为)。外观性改动不再触发重启;开启自动扩缩后改 ioConfig.taskCount 也不触发。
  • 重置到最新并回填:Kafka 与 RabbitMQ 的 supervisor 可以重置到最新 offset,并起一个 bounded backfill supervisor 去补被跳过的区间,适合「最新数据最重要」的告警类场景。条件是 useEarliestSequenceNumber 为 false、supervisor context 里 useConcurrentLocks 为 true(让回填任务与主任务并发写)、且处于 RUNNING 状态。入口是 POST /druid/indexer/v1/supervisor/{supervisorId}/resetToLatestAndBackfill 或 web console。
  • 查询 laning 新策略:weighted 策略按查询越过多少条阈值(段数、区间跨度、数据年龄、段范围)打分,分派到容量限制不同的梯度 lane,比原来的 high/low 二分更细。四个阈值权重 periodWeight、durationWeight、segmentCountWeight、segmentRangeWeight 可配,默认均为 1。
  • Kafka 空闲信号:cost-based autoscaler 原来用的 poll-idle ratio 只反映轮询耗时,看不出是否还有余量。新增 useUtilizationRatio,改用 1 - (avgProcessingRate / maxObservedRate)。扩缩容的升降温冷却时间也可以分开配。
  • 其他值得记的:diskNormalized 平衡策略的 utilizationThreshold 语义调整(调高=更宽容,调低=把各节点磁盘使用率压得更接近);MiddleManager 与 Indexer 重启后保持 enable/disable 状态(想要旧行为设 druid.worker.startAlwaysEnabled = true);INSERT INTO EXTERN 支持 assumeRoleArn;S3 摄取遇到 SSLException 与临时性凭据错误会重试而不是直接失败,S3 连接池默认大小改为按可用处理器数计算;新增 now() 表达式函数(逐行求值、非确定性,会破坏幂等);web console 支持把流式 supervisor 转成 SQL 摄取、支持重置与回填;druid.auth.emitAuthMetrics 打开后按 identity、authorizer、resource、action 等维度输出鉴权指标;新增 OpenLineage emitter 社区扩展;Kubernetes 扩展实验性支持单个 Overlord 跨多个 K8s 集群调度索引任务(druid.indexer.runner.type=multik8s)。
  • 指标口径变化:storage/load/bytes 与 storage/virtual/load/bytes 改为在加载完成后计量(原先是加载开始时),新增 storage/load/begin/bytes 系列承接原语义;cost-based autoscaler 移除 lagCost/idleCost,换成 avgProcessingRate、avgPollIdleRatio、lagWeight、costWeight。
  • 弃用预告:38 是最后一个支持读取 legacy v0.4–v0.7 ZSTD frame 的大版本。原因是底层 zstd-jni 从 1.5.7-13 起移除了这些旧 frame 的解码。批处理与流式摄取两侧的支持都会在后续版本移除。

行业影响

Druid 的实时段一直是「先写进来、查得到、但裁剪得等 compaction」的状态。把 dim_value_set 做进流式发布的段,等于把列存的裁剪能力前推到数据刚落地的那一刻,对以最新数据为主的告警与监控类负载是直接收益。代价是这份收益建立在一次性全量升级之上:新 shard spec 没有 fallback,一旦发布过就回不去,直到被 compaction 掉。这是一个把运维顺序写进功能开关的取舍——能力给你,但开关要你自己按顺序扳。

ZooKeeper 任务运行器的删除是另一类信号。它从 25.0.0 起就不是默认路径,只是没人正式关掉;这次关掉之后,配置里留着 remote 会直接启动失败。这类「把长期废弃路径正式删除」的变更,恰恰是升级事故最集中的地方——不是因为它复杂,是因为它藏在没人再看的配置里。

相关链接


AWS 两天两条公告:部分索引与过滤导出,都把筛选搬到写出之前

事件概述

10 月 2 日,Amazon Aurora DSQL 宣布支持部分索引(partial index):建索引时可以带 WHERE 子句,索引只包含满足条件的行。10 月 1 日,Amazon DynamoDB 宣布导出到 S3 支持过滤:可以用键条件表达式与过滤表达式选条目,用投影表达式选属性。

两条公告都不长,体量也谈不上大,但方向一致:在数据被写出之前就先筛掉不需要的那部分,而不是先全量落下来、再在查询侧过滤。前者发生在索引构建时,后者发生在导出写出时。放在湖仓侧已经成熟的 partition pruning、Iceberg 的 metrics 裁剪旁边看,这是同一条思路往事务库与导出通道上的延伸。

技术解析

  • Aurora DSQL 部分索引:CREATE INDEX 带 WHERE 子句,只为满足条件的行建索引条目。官方给的典型形态是「开放订单混在多年已完成订单里」——工作集很小、历史很大。索引只覆盖工作集,表继续增长时索引不会跟着线性变大;查询的过滤条件落在索引条件范围内时,Aurora DSQL 会自动使用这个部分索引,读的数据更少。在提供 Aurora DSQL 的所有区域可用。
  • 部分索引的收益边界:收益只落在过滤条件与索引条件相容的查询上。写路径上每行的索引维护多了一次谓词判断,换的是索引体积下降与写放大下降。这是拿一点写成本换索引尺寸与查询读量,不是无条件加速。
  • DynamoDB 过滤导出:导出到 S3 原本支持全量导出与按时间窗口的增量导出。加上过滤之后,可以用作用于键属性的 key condition expression 与作用于任意属性的 filter expression 决定导出哪些条目,用 projection expression 决定导出哪些属性。官方列出的用途有三类:细粒度数据恢复、把一段数据搬到另一个账号、在合规约束下做分析。全量导出与增量导出都支持,除 AWS GovCloud (US) 外的所有区域可用。
  • 过滤导出减少的是什么:它减少的是落到 S3 上的数据量,以及下游分析作业要读、要扫、要付存储费的那一半。它并没有把导出变成一次索引查找——过滤表达式作用在结果集上,扫描那一侧的代价不会因为加了过滤就消失。评估收益时盯的应该是「S3 上少落了多少」与「下游少读了多少」这两个数。
  • 两条公告的共同结构:一个谓词被提前到写出路径上,从「事后筛」变成「事前定」。区别只在承载这个谓词的东西是什么——一个是索引定义,一个是导出任务的参数。

行业影响

数据平台过去几年的成本控制,大部分是从「减少移动」里省出来的:列式裁剪、分区裁剪、谓词下推、缓存,都是让更少的字节穿过更少的环节。AWS 这两条把这个原则用在了两个此前没有下推口的环节——事务库的索引体积,以及导出通道的落地数据量。

对使用者来说,真正需要改的是评估方法。索引不再是「建了就更快」,而是「建了之后哪些查询会命中、索引会长多大」;导出不再是「定期全量倒一份」,而是「这一份里到底需要哪些条目与哪些属性」。这两个问题在以前都由下游承担,现在被推回到了定义这一侧。合规场景里这一点尤其明显:投影表达式让「只导出允许分析的那几列」变成导出任务本身的配置,而不是导出之后再补一道脱敏。

相关链接


ClickHouse:四条分支在 10 月 3 日四小时内各打一个补丁标签

事件概述

10 月 3 日 13:51 到 18:04(UTC)这四个小时里,ClickHouse 依次给四条分支打了标签:v26.3.40.16-lts、v26.7.20.28-stable、v26.8.16.41-lts、v26.9.9.28-stable。四条线在同一天各进一个补丁号。

这不是一次特别的发布,而是这个项目当前节奏的一个切片。往前数七天(9 月 27 日至 10 月 3 日),26.9 线从 v26.9.4.3-stable 走到 v26.9.9.28-stable,六个补丁号;26.3 这条 LTS 线从 v26.3.34.136-lts 走到 v26.3.40.16-lts,也是六个。也就是说,四条分支各自维持着接近每个工作日一次的补丁节奏,其中两条是 LTS。

技术解析

  • 四条并行分支:26.9 与 26.7 打 -stable 后缀,26.8 与 26.3 打 -lts 后缀。四条线在同一时间窗内都有补丁产出,说明维护范围不是「最新一条 + 一条 LTS」,而是多条线各自在走。
  • 版本号里的信息:以 v26.9.9.28-stable 为例,第三段是补丁序号,第四段在同一天内区分多次产出。读版本号时真正要区分的是前两段(分支)与后缀(stable / LTS),第三段只表示在这条分支上排到第几个补丁。
  • 发布页不携带可读差异:这几个标签的 GitHub release body 是空的——「发版」这个动作本身不附带一份可读的变更说明,具体内容要到 changelog 链接里看。这决定了跟进方式:订阅分支标签只能知道「有新版」,要知道「变了什么」必须点进 changelog。
  • 升级的含义变了:补丁密度到了每天一次的量级,升级就不再是「挑个季度窗口评审一次」的决策,而是一条需要被流程接住的流——镜像、Helm chart、内部制品库都要能按分支跟踪,而不是按「最新版本」跟踪。
  • 反向的一面:这也意味着修复到达使用者的路径很短。一个被报告并修复的问题,从合入到出现在某条分支的标签上,量级是天。对自维护部署来说,「等下个版本」这个说法在这条时间尺度上失去了意义。

行业影响

ClickHouse 这套节奏把版本管理的问题从「选哪个版本」换成了「选哪条分支,以及怎么跟上它」。分支选择是策略问题——26.9 这类 stable 线拿新特性,26.3 这类 LTS 线拿长期维护;跟上分支则是工程问题,需要自动化把 changelog 差异拉出来做回归判断,而不是人工看发布页。

值得留意的是补丁与特性的区分。补丁号每天在涨,不代表能力每天在变——把补丁序号当功能版本读,会得出完全错误的迁移判断。版本策略文档里应该写清两件事:跟踪哪条分支,以及补丁升级的验证门禁是什么。

相关链接


编者评

把这四件事放在一起,最清楚的一条线是「把判断往前挪」。iceberg-go 把扫描规划交给目录,Druid 把裁剪做进刚发布的实时段,AWS 把谓词塞进索引定义与导出任务,三者都是在数据被搬动之前先决定哪些不必搬;ClickHouse 那条看起来不相关,实则对应着另一半——当修复以天为单位到达时,「什么时候升级」这个判断本身也要往前挪,从人工评审挪到自动化门禁。值得留意的是三条技术动态全部附了代价:远端规划是 opt-in 且滚动升级期间有 variant 扩展名的时间窗,实时段裁剪要求先全量升级且发布后不能降级,部分索引只对条件相容的查询生效、过滤导出也不改变扫描侧的消耗。这些代价的共同点是它们都不在升级当下暴露——catalog/hadoop 的云 scheme 副作用要到运行期才炸,dim_value_set 的降级限制要等到你想回退时才撞上,索引命中率要等查询跑起来才知道。本期的另一层观察是「清账」正在成为大版本的主要内容:Druid 38 删除了 ZooKeeper 任务运行器与 Java 17 支持,iceberg-go 修掉 400 个缺陷并改掉一批接口拼写,ClickHouse 四条线每天各自推进一个补丁号。新能力没有停,但支撑新能力的那部分工作——把旧路径划掉、把错误修正、把接口收敛——正在占据越来越大的版面。