-
Notifications
You must be signed in to change notification settings - Fork 960
iceberg: cut shredder allocations, and add write/commit performance harnesses #4712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Jeffail
wants to merge
12
commits into
main
Choose a base branch
from
iceberg-shredder-allocations-and-benches
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,645
−5
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
17f8f54
iceberg: add throughput and profiling bench harnesses
Jeffail 2e80f3e
iceberg: cut two per-record map allocations from the shredder
Jeffail 42e4bc6
iceberg: add a commit-regime harness for latency-bound throughput
Jeffail 1bf1770
iceberg: address review — nested shredder coverage, goroutine assertions
Jeffail e9c8bd2
docs: record iceberg shredder and commit-regime benchmark results
Jeffail 3648961
iceberg: add an optional parquet compression codec
Jeffail ad6056f
iceberg: address review — codec casing, duplicate field names, doc reach
Jeffail e55a882
iceberg: fix a stale benchmark reference and unmeasured perf claims
Jeffail 0df23cd
iceberg: name the table in compression warnings, accept lz4_raw spelling
Jeffail e454787
iceberg: measure write-path throughput without the pipeline suite
Jeffail f82e5f1
iceberg: fix the throughput harness's codec expectation
Jeffail a26e7fe
iceberg: correct the warnedCompression field comment
Jeffail File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR changes the sink's hot path (the shredder) and adds a new knob that spends CPU per record (
parquet.compression), but no localhost or real-endpoint throughput number is re-measured — this section says so explicitly ("It has not been measured end to end — no throughput figure above or elsewhere in this file has been re-run for this change"), and there is no section at all for the compression codec.docs/benchmarking.mditem 2 asks for a re-run, not only an appended section: "When modifying a connector's performance path — Re-run the benchmark and append a new dated section to the results file. This includes changes to batching, buffering, connection handling, serialization, or any code that sits in the hot path." CONTRIBUTING §1.3.4 requires both phases (localhost and real-endpoint) and §1.3.5 requires runs at various throughput levels.The gap matters most for compression: the field docs assert "this output is per-record CPU bound at low core counts, so enabling it can cost throughput on a small deployment" — that is a performance claim shipped to users with no measurement behind it, on a connector where the bench harness to measure it (
task bench:profile,task bench) is right here in this PR.Suggested fix: run the existing localhost
benchsuite before/after the shredder change, and once more withparquet.compression: zstd, and append the dated sections. If a re-run is genuinely out of scope for this PR, say so in the PR description and link the follow-up.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the fairest hit in the review, and I can only half-fix it.
Taking the second half first, because you are right and it was the worse problem: the field docs asserted a throughput cost with nothing behind it. Reworded in
e55a882fto separate what is measured from what is not — profiling at one vCPU does attribute roughly a seventh of this output's CPU to parquet encoding and does find it CPU bound per record at low core counts, but the cost of any particular codec is unmeasured, so the docs now say that and tell the reader to measure their own workload rather than implying a known result.On the re-run itself: I tried, and I cannot produce it here. The localhost suite drives the
icebergoutput, which is an enterprise component, and the license on this machine expired on 2026-08-08 — the pipeline refuses to init the output and exits, so there is no before/after pair to be had. (Worth saying I only found that because I had the runner detect failures; the first run I did reported a perfectly plausible 36,846 msg/s that was in fact an immediate license-error exit. Any throughput number I had reported without that check would have been fiction.)So rather than leave the gap unexplained,
e55a882frecords it indocs/benchmark-results/iceberg.mdalongside the shredder section: what is missing, why, and exactly what to run once a current license is available —task benchbefore/after plus one run per codec, at one and four cores. Happy to run it and append the sections the moment I have a working license, and equally happy for that to gate the PR if you would rather the numbers land before it merges.One thing I would push back on gently: for the shredder change specifically, the sink-level effect is bounded above by profiling that already exists (~27% of CPU in shredding), and the isolated measurement is a benchstat A/B over n=8 with p=0.000. I do not think the end-to-end run would change the decision to make the change — it would size the win, which matters for the docs, not for whether the code is right. The compression knob is the one where measurement genuinely could change the recommended default, and that default is deliberately "uncompressed" precisely so nobody inherits an unmeasured cost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: got the numbers, from a different angle.
e4547874.The pipeline suite could not produce them, but it turns out the write path does not need it.
license.CheckRunningEnterpriseis called by the output constructor, not by the Router — so driving the Router against the containerised MinIO + REST catalog, exactly as the integration tests already do, measures JSON decode, shredding, parquet encode, upload and commit with no licence involved.TestWriteThroughputdoes that, and both sections are now indocs/benchmark-results/iceberg.md.Two results contradict what this branch previously asserted, so the docs are corrected rather than the results buried:
I also found something worth knowing independent of this PR: a table created through the Iceberg library — including tables this output creates itself — comes back carrying
write.parquet.compression-codec: zstd, materialised at creation. Since an unset field defers to the property, those tables get zstd, so the "uncompressed default" is narrower than the docs claimed. Corrected.Three things the harness asserts, because each one caught a plausible-looking lie: it fails unless the table holds exactly the records written (a run once reported 36,846 msg/s while exiting immediately on the licence error); it reads the data back to check columns are populated; and it reads the codec out of a written file footer and fails if it is not the one requested (which is how I found the "uncompressed" baseline was writing zstd). A bytes-per-record figure I initially took from the snapshot summary is also gone — this catalog reports 82kB for a table whose string column alone reads back as 528kB, so it is summed from the manifests now.
Caveats stated in the sections: n=1 per point, one machine, local object storage (which understates the case for compression rather than overstating it), and
GOMAXPROCS=1here constrains the writer while MinIO and the catalog have their own cores — so it is not a 1-vCPU deployment. The full-pipeline figures higher up the file are still not re-run; that suite does need the licence.