Skip to content

feat(storage): default parquet codec to zstd for flink and spark 3.5+ - #19685

Open
cshuo wants to merge 2 commits into
apache:masterfrom
cshuo:use_zstd_codec
Open

feat(storage): default parquet codec to zstd for flink and spark 3.5+#19685
cshuo wants to merge 2 commits into
apache:masterfrom
cshuo:use_zstd_codec

Conversation

@cshuo

@cshuo cshuo commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Describe the issue this Pull Request addresses

Closes #19684.

Flink and Spark 3.5+ currently default Parquet base and native log files to GZIP, which provides a good compression ratio but adds significant CPU overhead to the write path. ZSTD offers a better balance of compression throughput and storage efficiency. Spark 3.3/3.4 require a compatibility exception because Hudi's non-vectorized file-group reader can still encounter the PARQUET-2160 off-heap leak when reading ZSTD files.

This implements the engine- and runtime-specific behavior discussed in #19615.

Summary and Changelog

  • Change the storage-level default of hoodie.parquet.compression.codec to zstd.
  • Resolve the effective default in HoodieStorageConfig according to the engine:
    • Flink: zstd
    • Spark 3.5 and newer, including Spark 4.x: zstd
    • Spark older than 3.5 or when the runtime version cannot be determined: gzip
    • Java and other engines: gzip
  • Pass the engine type through HoodieWriteConfig, Flink write-client construction, metadata table-service configuration, and Spark binary-copy clustering configuration.
  • Preserve explicitly configured codecs in derived write configurations, including metadata writes and binary-copy clustering fallback.
  • Add com.github.luben:zstd-jni to the Flink bundle shade includes.
  • Continue relying on the Spark runtime for zstd-jni instead of packaging another copy in Spark bundles.
  • Keep the Spark-to-Hive bundle validation write on GZIP because its Alpine-based environment cannot load Hadoop's native ZSTD library.

Impact

This changes the default compression codec for newly written Parquet base files and native Parquet log blocks when using Flink or Spark 3.5 and newer. Existing files remain readable, and tables may contain files using different compression codecs.

Risk Level

Medium.

The default codec changes the physical encoding of newly written Parquet files for Flink and Spark 3.5+ workloads. The risk is mitigated by retaining GZIP for older Spark and Java runtimes, preserving explicit user configuration, packaging the required JNI dependency in the Flink bundle, and validating the engine-specific defaults and derived configuration paths.

Documentation Update

Updated the root build documentation, Spark datasource documentation, and configuration description to document the engine/version-specific defaults and the PARQUET-2160 risk for Spark 3.3 and 3.4.

Contributor's checklist

  • Read through contributor's guide
  • Enough context is provided in the sections above
  • Adequate tests were added if applicable

@github-actions github-actions Bot added the size:M PR with lines of changes in (100, 300] label Aug 20, 2026
@codecov-commenter

codecov-commenter commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 78.00%. Comparing base (e0fe585) to head (8355a26).
⚠️ Report is 25 commits behind head on master.

Files with missing lines Patch % Lines
...java/org/apache/hudi/config/HoodieWriteConfig.java 93.33% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #19685      +/-   ##
============================================
+ Coverage     77.88%   78.00%   +0.11%     
- Complexity    33264    33494     +230     
============================================
  Files          2533     2539       +6     
  Lines        140342   141058     +716     
  Branches      16912    17175     +263     
============================================
+ Hits         109310   110032     +722     
+ Misses        23401    23361      -40     
- Partials       7631     7665      +34     
Components Coverage Δ
hudi-common 83.47% <100.00%> (+0.12%) ⬆️
hudi-client 83.08% <93.75%> (+0.09%) ⬆️
hudi-flink 85.67% <ø> (+0.08%) ⬆️
hudi-spark-datasource 72.38% <ø> (+0.01%) ⬆️
hudi-utilities 74.38% <ø> (+0.04%) ⬆️
hudi-cli 15.06% <ø> (ø)
hudi-hadoop 69.45% <ø> (+0.36%) ⬆️
hudi-sync 75.54% <ø> (+0.04%) ⬆️
hudi-io 80.00% <ø> (+0.23%) ⬆️
hudi-timeline-service 83.54% <ø> (+0.09%) ⬆️
hudi-cloud 64.27% <ø> (-0.06%) ⬇️
hudi-kafka-connect 53.96% <ø> (+0.76%) ⬆️
Flag Coverage Δ
common-and-other-modules 51.07% <95.45%> (+0.12%) ⬆️
flink-integration-tests 49.02% <68.18%> (-0.10%) ⬇️
hadoop-mr-java-client 43.79% <68.18%> (-0.11%) ⬇️
spark-client-hadoop-common 50.55% <63.63%> (-0.06%) ⬇️
spark-java-tests 52.03% <68.18%> (+0.06%) ⬆️
spark-scala-tests 46.67% <68.18%> (+0.16%) ⬆️
utilities 36.41% <63.63%> (-0.13%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...apache/hudi/metadata/HoodieMetadataWriteUtils.java 94.44% <100.00%> (+0.02%) ⬆️
...va/org/apache/hudi/common/config/HoodieConfig.java 95.41% <100.00%> (+0.12%) ⬆️
...apache/hudi/common/config/HoodieStorageConfig.java 89.30% <100.00%> (-0.79%) ⬇️
...java/org/apache/hudi/config/HoodieWriteConfig.java 92.09% <93.33%> (+0.01%) ⬆️

... and 73 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cshuo
cshuo marked this pull request as ready for review August 27, 2026 08:07

@hudi-agent hudi-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.

Thanks for working on this! The PR switches the default Parquet compression codec to ZSTD for Flink and Spark 3.5+, resolving the effective default per-engine in HoodieStorageConfig with a safe GZIP fallback, and threads engine type through the write config, Flink client, metadata write config, and binary-copy clustering fallback. The resolution logic and fallbacks look correct and are well covered by tests; one forward-looking question is noted inline. Please take a look at any inline comments, and this should be ready for a Hudi committer or PMC member to take it from here. A few small nits below, but overall the code is clean and well-documented.


public static class Builder {

private EngineType engineType = EngineType.SPARK;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 nit: since .parquetCompressionCodec(writeConfig.getParquetCompressionCodec()) is always called explicitly at every callsite that resets the codec (e.g. SparkBinaryCopyClusteringExecutionStrategy), the engineType field in the Builder is effectively only consulted when no explicit value is set. That's the intended fast-path, but worth a brief comment here (or on build()) explaining that the engine default only fires when the codec key is absent from props — could save a future reader some head-scratching.

⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.

static String getDefaultParquetCompressionCodec(EngineType engineType) {
switch (engineType) {
case FLINK:
return ZSTD_COMPRESSION_CODEC;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 nit: could you flip the name to ZSTD_DEFAULT_MIN_SPARK_VERSION (or MIN_SPARK_VERSION_FOR_ZSTD_DEFAULT)? The current MIN_SPARK_VERSION_WITH_ZSTD_DEFAULT reads as "minimum Spark version that has a ZSTD default", which is accurate, but the more common Hudi constant style puts the subject concept first — makes scanning constants easier.

⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Line 543: The builder defaults engineType to SPARK, so any caller that builds a HoodieStorageConfig without withEngineType(...) resolves the codec via Spark-runtime reflection, making the effective default zstd on any classpath that happens to have Spark 3.5+, even in a Java/Flink context. All three production call sites are patched here, but would it be safer to default this to GZIP when the engine is not explicitly provided, so a future caller that forgets withEngineType fails safe rather than silently writing zstd?

⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.

Comment thread packaging/hudi-flink-bundle/pom.xml
@hudi-bot

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands @hudi-bot supports the following commands:
  • @hudi-bot run azure re-run the last Azure build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M PR with lines of changes in (100, 300]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Default Parquet codec to ZSTD for Flink and Spark 3.5+

5 participants