news 2026/10/24 1:42:01

Apache Iceberg JMH 基准测试完全指南:从 GitHub Actions 到本地 Spark 读写基准

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache Iceberg JMH 基准测试完全指南:从 GitHub Actions 到本地 Spark 读写基准
  • 数据湖
  • 湖仓一体
  • 大数据

【免费下载链接】iceberg

Apache Iceberg

项目地址:https://gitcode.com/gh_mirrors/iceberg5/iceberg
点击查看免费下载

Apache Iceberg 项目内置了一套基于 JMH(Java Microbenchmark Harness)的基准测试体系,用于量化 Spark + Iceberg 在读、写、过滤、向量化读取等场景下的性能表现,并与 Spark 内置 file source 直接对比。本文以 site/docs/benchmarks.md 为主线,结合仓库中的 jmh.gradle、.github/workflows/jmh-benchmarks.yml 以及spark/*/spark/src/jmh目录下的 benchmark 源码,完整讲解 Iceberg JMH 基准测试的组成、GitHub Actions 云端运行方式、本地 Gradle 命令,以及每个 benchmark 的评测目标与底层实现要点,帮助你快速上手并正确解读测试结果。

一、JMH 基准测试在 Iceberg 仓库中的位置与运行约定

1.1 Benchmark 源码的存放目录

Iceberg 仓库中所有 JMH benchmark 的 Java 源码统一放在各模块的src/jmh/java目录下,而不是src/main/java或src/test/java:

  • core 模块:core/src/jmh/java/org/apache/iceberg(例如ManifestReadBenchmark、ZOrderByteUtilsBenchmark、metrics/CountersBenchmark);
  • data 模块:data/src/jmh/java/org/apache/iceberg(例如GenericParquetReaderBenchmark、GenericOrcReaderBenchmark、ReaderBenchmark);
  • Spark 模块:spark/v3.3|v3.4|v3.5/spark/src/jmh/java/org/apache/iceberg/spark下,按source/avro、source/orc、source/parquet、source/parquet/vectorized、data/parquet等目录组织,分别对应不同的数据源与读写路径;
  • Flink 模块:flink/v1.17|v1.18|v1.19/flink/src/jmh下也有对应 benchmark(如 flink/v1.19/flink/src/jmh)。

文档明确建议:只运行你关心的 benchmark,而不是一次性跑完所有测试。这是因为 JMH 基准测试本身耗时较长,且某些 benchmark 的数据集规模很大(例如单文件 1000 万行),全量运行会浪费大量计算资源。

1.2 两个重要的运行约定

关联文档特别强调两点,理解它们对解读结果至关重要:

  1. JMH benchmark 与被测系统运行在同一个 JVM 中。这意味着 JIT 编译、GC、类加载、线程调度等 JVM 内部行为会直接影响测量结果,因此不同运行之间结果可能有所波动;
  2. 结果应视为"变化趋势的指示器"而非绝对性能标尺。由于存在运行间波动,不应直接根据单次 benchmark 结果去推断生产环境中的选型决策。

此外,jmh.gradle 对运行环境还有硬性约束:

if (jdkVersion != '8' && jdkVersion != '11' && jdkVersion != '17') { throw new GradleException("The JMH benchmarks must be run with JDK 8 or JDK 11 or JDK 17") }

即JMH 基准测试必须使用 JDK 8、JDK 11 或 JDK 17运行,其他 JDK 版本会直接抛出 GradleException。这与仓库 CI(GitHub Actions 使用zulu发行版 JDK 11)保持一致。

二、在 GitHub Actions 上运行 Iceberg JMH 基准测试

2.1 通过 "JMH Benchmarks" 工作流手动触发

Iceberg 提供了开箱即用的 GitHub Actions 工作流 .github/workflows/jmh-benchmarks.yml,你可以在自己 fork 的 Iceberg 仓库上手动触发(workflow_dispatch)。工作流需要提供三个输入参数:

输入参数含义示例
repo要运行基准测试的仓库名(含 owner)apache/iceberg或<user>/iceberg
ref要运行基准测试的分支名master或my-cool-feature-branch
benchmarks逗号分隔的、带双引号的 Benchmark 类名列表"IcebergSourceFlatParquetDataReadBenchmark", "IcebergSourceFlatParquetDataFilterBenchmark"

另有可选的spark_version输入,默认值为iceberg-spark-3.5,用于指定要运行的 Spark 项目版本(如iceberg-spark-3.5)。

工作流的执行逻辑如下:

  • matrix 任务:先 checkout 指定仓库和分支,然后用jq解析benchmarks输入,筛选出所有以Benchmark结尾的类名,构造一个运行矩阵;
  • run-benchmark 任务:对矩阵中的每一个 benchmark,在ubuntu-22.04上执行:
./gradlew :iceberg-spark:<spark_version>:jmh \ -PjmhIncludeRegex=<Benchmark类名> \ -PjmhOutputPath=benchmark/<Benchmark类名>.txt
  • 上传结果:使用actions/upload-artifact@v4在所有 benchmark 完成后(if: ${{ always() }},即使失败也会上传)把**/benchmark/*.txt作为名为benchmark-results的 artifact 上传。

工作流还做了两件环境准备:通过actions/setup-java@v4安装 Zulu JDK 11,并将容器内的eth0IP 与主机名写入/etc/hosts,以保证 Spark local 模式在 CI 环境中正常解析网络地址。

2.2 定时基准测试工作流

除了手动触发,仓库还维护了另一个定时工作流 .github/workflows/recurring-jmh-benchmarks.yml,通过 cron 表达式0 0 * * 0在每周日 00:00 UTC自动运行一组精选的 benchmark(仅当仓库 owner 为apache时生效)。其矩阵固定为iceberg-spark-3.5版本的 15 个 benchmark,涵盖 Parquet 读写、过滤器、删除文件(Eq/Pos/Multi/Unrelated Delete)等场景,且该工作流额外传入了-PjmhJsonOutputPath以同时输出 JSON 结果。

2.3 对 CI 结果的正确态度

关联文档明确提醒:GitHub Actions 的 runner 资源有限,因此:

  • 结果只能作为帮助开发者理解代码变更的参考指标;
  • 不同运行之间存在明显的结果波动性;
  • 不应用 CI 结果来形成生产环境选型假设。

这正是 1.2 节所述"同 JVM 测量 + 资源受限"双重因素下的必然结论。

三、在本地运行 Iceberg JMH 基准测试

3.1 Gradle 属性与任务机制

本地运行的核心命令模式统一为:

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh \ -PjmhIncludeRegex=<Benchmark类名> \ -PjmhOutputPath=benchmark/<结果文件名>.txt

其中:iceberg-spark:iceberg-spark[2|3]表示在 Spark 2 或 Spark 3 系列模块中选择对应的 Gradle 子项目(文档中的命令为泛化写法;实际执行时需要替换为具体版本,例如:iceberg-spark:iceberg-spark-3.5_2.12)。三个关键 Gradle 属性在 gradle.properties 中都有默认值:

Gradle 属性默认值作用
jmhOutputPathbuild/reports/jmh/human-readable-output.txtJMH 人类可读文本结果输出路径
jmhJsonOutputPathbuild/reports/jmh/results.jsonJMH JSON 结果输出路径
jmhIncludeRegex.*匹配要运行的 benchmark 的正则表达式

从 jmh.gradle 的配置可以看到任务的具体行为:

jmh { jmhVersion = '1.37' failOnError = true forceGC = true includeTests = true humanOutputFile = file(jmhOutputPath) resultsFile = file(jmhJsonOutputPath) resultFormat = 'JSON' includes = [jmhIncludeRegex] zip64 = true }

要点解读:

  • JMH 版本固定为 1.37;
  • failOnError = true:任何 benchmark 运行出错都会导致构建失败,避免静默吞掉错误;
  • forceGC = true:每次迭代前强制执行 GC,降低 GC 噪声对测量的影响;
  • 结果同时输出人类可读文本(humanOutputFile)和JSON(resultsFile,格式resultFormat = 'JSON');
  • 任务执行完毕后,tasks.jmh.finalizedBy tasks.jmhReport会自动生成 JMH 报告(HTML 形式,输出在 JSON 路径去掉.json后缀的目录中)。

另外,jmh.gradle会根据系统属性sparkVersions(默认取defaultSparkVersions)决定将哪些模块纳入 JMH 构建:3.3、3.4、3.5各自对应:iceberg-spark:iceberg-spark-X_<scalaVersion>与:iceberg-spark:iceberg-spark-extensions-X_<scalaVersion>两个项目。从源码注释可见,针对某个具体版本运行时可显式指定,例如:

./gradlew -DsparkVersions=3.5 :iceberg-spark:iceberg-spark-3.5_2.12:jmh \ -PjmhIncludeRegex=IcebergSourceFlatParquetDataReadBenchmark \ -PjmhOutputPath=benchmark/iceberg-source-flat-parquet-data-read-benchmark-result.txt

3.2 Benchmark 公共配置注解

无论是 Spark source 类 benchmark 还是纯 Writer 类 benchmark,其 JMH 注解配置保持一致(可在 IcebergSourceBenchmark.java 与 SparkParquetWritersFlatDataBenchmark.java 中看到):

@Fork(1) // 单 fork,避免多次 JVM 启动开销 @State(Scope.Benchmark) // benchmark 级共享状态 @Warmup(iterations = 3) // 3 次预热迭代 @Measurement(iterations = 5) // 5 次正式测量迭代 @BenchmarkMode(Mode.SingleShotTime) // 单次执行计时模式

Mode.SingleShotTime意味着每次迭代只执行一次被测方法并测量其耗时,适合数据规模大、单次执行耗时长的场景(如写 2000 万行数据)。所有被测方法均使用@Threads(1)单线程执行,以消除并发调度带来的干扰。

四、19 个本地 benchmark 逐个详解

以下按关联文档的顺序,完整列出所有本地 benchmark 的评测目标与运行命令。每个命令中[2|3]表示可在 Spark 2 或 Spark 3 系列模块中选择对应 Gradle 子项目执行;你也可以参照上文显式指定-DsparkVersions=3.5与iceberg-spark-3.5_2.12。

4.1 嵌套 List 结构 Parquet 写入

评测 Iceberg 与 Spark 内置 file source 在嵌套 List 数据 Parquet 写入上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceNestedListParquetDataWriteBenchmark -PjmhOutputPath=benchmark/iceberg-source-nested-list-parquet-data-write-benchmark-result.txt

源码 IcebergSourceNestedListParquetDataWriteBenchmark.java 继承自 IcebergSourceNestedListDataBenchmark.java,后者定义了id+outerlist<struct<innerlist<list<string>>>>的嵌套 schema,并设置METADATA_COMPRESSION=gzip。被测方法通过@Param({"2000", "20000"})分别在 2000 行与 20000 行两个数据规模下,对比writeIceberg()(format("iceberg")追加写入)与writeFileSource()(设置 gzip 压缩后直接写 Parquet)两条路径。

4.2 Spark Parquet Readers 嵌套数据读取

评测 Iceberg 与 Spark Parquet reader 在嵌套 Parquet 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=SparkParquetReadersNestedDataBenchmark -PjmhOutputPath=benchmark/spark-parquet-readers-nested-data-benchmark-result.txt

源码位于 SparkParquetReadersNestedDataBenchmark.java(同目录下还有SparkParquetReadersFlatDataBenchmark),属于纯 reader 层对比:使用RandomData.generateSpark生成随机行,分别用 Iceberg 的Parquet.read(...).project(SCHEMA).createReaderFunc(...)与 Spark 的向量化 reader 读取同一份 Parquet 文件。

4.3 Spark Parquet Writers 扁平数据写入

评测 Iceberg 与 Spark Parquet writer 在扁平 schema Parquet 写入上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=SparkParquetWritersFlatDataBenchmark -PjmhOutputPath=benchmark/spark-parquet-writers-flat-data-benchmark-result.txt

源码 SparkParquetWritersFlatDataBenchmark.java 定义了 8 列(long/int/float/double/decimal/date/timestamp/string)的扁平 schema,用RandomData.generateSpark生成 100 万条记录,对比:

  • writeUsingIcebergWriter():通过Parquet.write(...).createWriterFunc(...)传入SparkParquetWriters.buildWriter,走 Iceberg 的 Spark 写入适配层;
  • writeUsingSparkWriter():通过Parquet.write(...).writeSupport(new ParquetWriteSupport())并设置spark.sql.parquet.writeLegacyFormat、outputTimestampType=TIMESTAMP_MICROS、fieldId.write.enabled=false等参数,模拟 Spark 原生写入路径。

4.4 Iceberg Source 扁平 ORC 数据读取

评测 Iceberg 与 Spark 内置 file source 在扁平 ORC 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceFlatORCDataReadBenchmark -PjmhOutputPath=benchmark/iceberg-source-flat-orc-data-read-benchmark-result.txt

源码 IcebergSourceFlatORCDataReadBenchmark.java 生成 10 个文件、每文件 100 万行的扁平数据集,对比readIceberg()(format("iceberg"))与readFileSource()(直接orc(dataLocation()))两条读取路径。同目录的 IcebergSourceFlatORCDataBenchmark.java 是共享基类,负责 ORC 表的创建与数据追加。

4.5 Spark Parquet Readers 扁平数据读取

评测 Iceberg 与 Spark Parquet reader 在扁平 Parquet 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=SparkParquetReadersFlatDataBenchmark -PjmhOutputPath=benchmark/spark-parquet-readers-flat-data-benchmark-result.txt

4.6 向量化读取字典编码的扁平 Parquet

对比 Iceberg向量化读取路径与 Spark 内置 file source 在字典编码扁平 Parquet上的读取性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=VectorizedReadDictionaryEncodedFlatParquetDataBenchmark -PjmhOutputPath=benchmark/vectorized-read-dict-encoded-flat-parquet-data-result.txt

源码 VectorizedReadDictionaryEncodedFlatParquetDataBenchmark.java 继承自VectorizedReadFlatParquetDataBenchmark,差异在于:

  • setupBenchmark()调用setupSpark(true)开启字典编码(默认关闭字典编码,强制走 plain 编码);
  • 数据生成时对 long/int/float/double/decimal(18,5)/date/timestamp/string 各列用pmod(id, 9)制造低基数值以触发字典编码;bigDecimalCol(decimal(20,5))在 Parquet v1 中以固定长度二进制存储,天然不适用字典编码,作为对照列保留。

4.7 嵌套 List 结构 ORC 写入

评测 Iceberg 与 Spark 内置 file source 在嵌套 List 数据 ORC 写入上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceNestedListORCDataWriteBenchmark -PjmhOutputPath=benchmark/iceberg-source-nested-list-orc-data-write-benchmark-result.txt

源码 IcebergSourceNestedListORCDataWriteBenchmark.java 与 4.1 的 Parquet 版本结构对称,但额外包含三个方法:writeIceberg()(write-format=orc)、writeIcebergDictionaryOff()(通过表属性orc.dictionary.key.threshold=0关闭 ORC 字典编码后写入)以及writeFileSource()。

4.8 向量化读取扁平 Parquet

对比 Iceberg向量化读取路径与 Spark 内置 file source 在扁平 Parquet上的读取性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=VectorizedReadFlatParquetDataBenchmark -PjmhOutputPath=benchmark/vectorized-read-flat-parquet-data-result.txt

源码 VectorizedReadFlatParquetDataBenchmark.java 是向量化基准的核心基类:

  • 数据集规模为5 个文件 × 每文件 1000 万行(NUM_FILES = 5,NUM_ROWS_PER_FILE = 10_000_000);
  • 表写入属性设置METADATA_COMPRESSION=gzip与PARQUET_DICT_SIZE_BYTES=1(把字典页大小压到 1 字节,避免字典编码干扰);
  • 对 intCol/longCol/floatCol/doubleCol/decimalCol/bigDecimalCol/dateCol/timestampCol/stringCol9 种列类型分别提供一对方法:readXxxIcebergVectorized5k()通过表属性开启 Iceberg 向量化(PARQUET_VECTORIZATION_ENABLED=true、PARQUET_BATCH_SIZE=5000),readXxxSparkVectorized5k()通过 Spark SQL 配置开启 Spark 向量化(spark.sql.parquet.enableVectorizedReader=true、批大小 5000)。

4.9 Iceberg Source 扁平 Parquet 写入

评测 Iceberg 与 Spark 内置 file source 在扁平 Parquet 写入上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceFlatParquetDataWriteBenchmark -PjmhOutputPath=benchmark/iceberg-source-flat-parquet-data-write-benchmark-result.txt

4.10 Iceberg Source 嵌套 Avro 数据读取

评测 Iceberg 与 Spark 内置 file source 在嵌套 Avro 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceNestedAvroDataReadBenchmark -PjmhOutputPath=benchmark/iceberg-source-nested-avro-data-read-benchmark-result.txt

源码位于 iceberg-spark 的 avro 目录,其中IcebergSourceFlatAvroDataReadBenchmark.java采用DEFAULT_FILE_FORMAT+SPLIT_OPEN_FILE_COST=128MB的表属性组合,对比 Iceberg 读取与 Spark 直接读 Avro 的性能。

4.11 Iceberg Source 扁平 Avro 数据读取

评测 Iceberg 与 Spark 内置 file source 在扁平 Avro 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceFlatAvroDataReadBenchmark -PjmhOutputPath=benchmark/iceberg-source-flat-avro-data-read-benchmark-result.txt

4.12 Iceberg Source 嵌套 Parquet 写入

评测 Iceberg 与 Spark 内置 file source 在嵌套 Parquet 写入上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceNestedParquetDataWriteBenchmark -PjmhOutputPath=benchmark/iceberg-source-nested-parquet-data-write-benchmark-result.txt

4.13 Iceberg Source 嵌套 Parquet 数据读取

评测 Iceberg 与 Spark 内置 file source 在嵌套 Parquet 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceNestedParquetDataReadBenchmark -PjmhOutputPath=benchmark/iceberg-source-nested-parquet-data-read-benchmark-result.txt

4.14 Iceberg Source 嵌套 ORC 数据读取

评测 Iceberg 与 Spark 内置 file source 在嵌套 ORC 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceNestedORCDataReadBenchmark -PjmhOutputPath=benchmark/iceberg-source-nested-orc-data-read-benchmark-result.txt

4.15 Iceberg Source 扁平 Parquet 数据读取

评测 Iceberg 与 Spark 内置 file source 在扁平 Parquet 数据读取上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceFlatParquetDataReadBenchmark -PjmhOutputPath=benchmark/iceberg-source-flat-parquet-data-read-benchmark-result.txt

源码 IcebergSourceFlatParquetDataReadBenchmark.java 是理解读取基准实现的最佳范例:

  • 数据为 10 个文件 × 每文件 100 万行的扁平 schema(long/int/float/double/decimal/date/timestamp/string 八列),通过appendAsFile()逐文件写入 Iceberg 表;
  • 五个被测方法分别覆盖:readIceberg()(Iceberg 全量读取)、readFileSourceVectorized()/readFileSourceNonVectorized()(Spark 向量化开/关的 file source 读取)、readWithProjectionIceberg()与readWithProjectionFileSource*()(只投影longCol一列的列裁剪读取);
  • 对比前会设置SPLIT_OPEN_FILE_COST=128MB(Iceberg 侧)或spark.sql.files.openCostInBytes=128MB(Spark 侧),保证两者在文件合并策略上口径一致。

4.16 Iceberg Source 扁平 Parquet 过滤基准

评测Spark 数据源中 Iceberg 的 file skipping(文件跳过)能力。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceFlatParquetDataFilterBenchmark -PjmhOutputPath=benchmark/iceberg-source-flat-parquet-data-filter-benchmark-result.txt

源码 IcebergSourceFlatParquetDataFilterBenchmark.java 是理解 Iceberg 元数据裁剪能力的关键基准:

  • 数据集为 499 个文件 × 每文件 1 万行,dateCol按文件序号递增(date_add(current_date(), fileNum)),使记录沿过滤谓词所用的列聚集;
  • 过滤条件固定为FILTER_COND = "dateCol == date_add(current_date(), 1)",即只命中第 1 个文件;
  • 三个被测方法对比:readWithFilterIceberg()依赖 Iceberg 元数据(manifest + partition stats)在读取前跳过 498 个文件;readWithFilterFileSourceVectorized()与readWithFilterFileSourceNonVectorized()则让 Spark file source 在列统计层面做 row-group 过滤,且不享受文件级跳过。

4.17 Iceberg Source 嵌套 Parquet 过滤基准

评测 Iceberg 数据源在嵌套数据上的 file skipping 能力。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=IcebergSourceNestedParquetDataFilterBenchmark -PjmhOutputPath=benchmark/iceberg-source-nested-parquet-data-filter-benchmark-result.txt

与 4.16 逻辑一致,区别在于数据为嵌套 schema,且记录同样沿过滤谓词列聚集,用于验证嵌套结构下的文件跳过效果。

4.18 Spark Parquet Writers 嵌套数据写入

评测 Iceberg 与 Spark Parquet writer 在嵌套 Parquet 写入上的性能。

./gradlew :iceberg-spark:iceberg-spark[2|3]:jmh -PjmhIncludeRegex=SparkParquetWritersNestedDataBenchmark -PjmhOutputPath=benchmark/spark-parquet-writers-nested-data-benchmark-result.txt

4.19 关于结果输出

上述命令中-PjmhOutputPath指定的文本文件即为 JMH 的人类可读结果;同时默认会在build/reports/jmh/results.json输出 JSON 结果,并自动生成 HTML 报告。如果你想用 recurring-jmh-benchmarks.yml 的方式把结果落到指定目录,可追加-PjmhJsonOutputPath=benchmark/<名称>.json参数。

五、更多进阶素材:删除文件与 Writer 层基准

关联文档列出的 19 个命令之外,仓库的 jmh 目录还沉淀了更多同体系基准,可作为深入阅读的入口:

  • 删除文件系列(位于 spark/v3.5/spark/src/jmh/java/org/apache/iceberg/spark/source/parquet):IcebergSourceParquetEqDeleteBenchmark(equality delete)、IcebergSourceParquetPosDeleteBenchmark(position delete)、IcebergSourceParquetMultiDeleteFileBenchmark(多删除文件)、IcebergSourceParquetWithUnrelatedDeleteBenchmark(无关删除文件),均已在每周定时工作流中运行;
  • Writer 层基准WritersBenchmark.java:直接对比ClusteredDataWriter、FanoutDataWriter、UnpartitionedWriter、SparkPartitionedWriter等 Iceberg 写入器在分区分桶(bucket(32))与未分区两种 spec 下的表现,还覆盖ClusteredEqualityDeleteWriter、ClusteredPositionDeleteWriter(PARTITION/FILE 两种DeleteGranularity)与FanoutPositionOnlyDeleteWriter(含 shuffle 与未 shuffle 两种位置删除顺序);
  • core/data 模块基准:如 core/src/jmh/java/org/apache/iceberg/ManifestReadBenchmark.java(manifest 读取)、data/src/jmh/java/org/apache/iceberg/GenericParquetReaderBenchmark.java(通用 Parquet reader)。

六、结语与最佳实践建议

综合关联文档与源码实现,使用 Iceberg JMH 基准测试时建议遵循以下原则:

  1. 按需运行:用-PjmhIncludeRegex=<类名>精确指定单个 benchmark,避免全量运行浪费算力;
  2. 固定环境:必须使用 JDK 8/11/17(jmh.gradle 强制校验);尽量在相同机器、相同数据规模下对比多次运行,观察趋势而非绝对值;
  3. 理解口径:多数 benchmark 是"一对多"设计(一个 Iceberg 路径对比 Spark file source 的向量化/非向量化路径),且通过SPLIT_OPEN_FILE_COST与spark.sql.files.openCostInBytes等参数对齐比较口径;
  4. CI 结果仅作参考:GitHub Actions runner 资源受限,其结果适合辅助代码评审与变更分析,不应直接用于生产选型决策;
  5. 结合 JSON 与报告:文本结果便于快速阅读,results.json与自动生成的 HTML 报告便于长期留存和横向对比。

通过本地命令或 fork 上的 JMH 工作流,你可以随时复现上述任一基准,将性能指标纳入 Iceberg 的日常开发与优化循环中。

  • 数据湖
  • 湖仓一体
  • 大数据

【免费下载链接】iceberg

Apache Iceberg

项目地址:https://gitcode.com/gh_mirrors/iceberg5/iceberg
点击查看免费下载

相关推荐

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 1:41:27

Spring RestTemplate配置与HTTP通信最佳实践

1. 为什么我们需要RestTemplate在分布式系统开发中&#xff0c;服务间的HTTP通信就像城市间的快递网络。RestTemplate就是Spring框架为我们准备的"标准化快递车"&#xff0c;它封装了HTTP请求的复杂性&#xff0c;让我们可以用面向对象的方式完成服务调用。我见过太多…

作者头像 李华
网站建设 2026/10/17 8:46:08

MobileNet与ShuffleNet为什么快?轻量网络设计背后的工程真相

先讲一个真实的工作场景&#xff1a;某项目需要在低算力的嵌入式设备上部署一个图像分类模型&#xff0c;一开始直接搬了标准卷积网络&#xff0c;帧率惨不忍睹。后来负责人说换成MobileNet试试&#xff0c;果真快了不少&#xff0c;但奇怪的是&#xff0c;测出来的FLOPs降了接…

作者头像 李华
网站建设 2026/10/22 6:50:56

血细胞检测全链路实战:YOLO数据集、训练与C++推理详解

简介&#xff1a;面向血液细胞图像智能分析场景&#xff0c;这份基于YOLO11的目标检测资源包&#xff0c;聚焦血小板、红细胞、白细胞等血液细胞的识别与定位&#xff0c;辅助血液疾病诊断研究&#xff0c;适合医学图像处理开发者、算法学习者及科研人员使用。包内共1854个文件…

作者头像 李华
网站建设 2026/10/18 17:50:09

STM32F103ZET6驱动GM65二维码模块实战:UART协议、波特率同步与硬件流控

简介&#xff1a;本资源是一套基于STM32F103ZET6微控制器驱动二维码识别模块GM65的完整嵌入式开发工程&#xff0c;面向嵌入式初学者、单片机课程设计者及物联网终端开发人员&#xff0c;解决二维码实时采集、串口通信解析与主控逻辑响应等典型应用问题。压缩包共188个文件&…

作者头像 李华
网站建设 2026/10/22 16:15:08

Agent-Reach:让AI Agent触达外部系统可控、透明、可靠

"Agent-Reach"这个词&#xff0c;我琢磨了大概两个月&#xff0c;差不多从第一版Demo到最近终于跑稳定&#xff0c;中间踩了不少坑。它不是一个花哨的Agent框架&#xff0c;也不是又一个人设对话工具&#xff0c;它解决的是个特别朴素但特别麻烦的问题&#xff1a;当…

作者头像 李华