Repository navigation
Conversation
ForVic
force-pushed
the
columnar-shuffle-batch-bytes
branch
from
October 14, 2026 04:11
fe95e4b to
8dec0ac
Compare
ForVic
force-pushed
the
columnar-shuffle-batch-bytes
branch
2 times, most recently
from
October 14, 2026 06:59
7162594 to
007f5ab
Compare
ForVic
force-pushed
the
columnar-shuffle-batch-bytes
branch
from
October 14, 2026 19:23
007f5ab to
5231565
Compare
ForVic
marked this pull request as ready for review
October 14, 2026 19:23
The columnar hash writer buffers one batch per reduce partition and only pushes it after `celeborn.columnarShuffle.batch.size` rows. With wide rows, or when a map task has fewer rows per partition than the batch size, the whole map output stays on the heap until the task ends. Add `celeborn.columnarShuffle.batch.sizeInBytes.enabled` (default false) and `celeborn.columnarShuffle.batch.sizeInBytes.threshold` (default 64k, the same as `celeborn.client.push.buffer.max.size`). When enabled, a batch is also pushed once the uncompressed size of its rows reaches the threshold.
ForVic
force-pushed
the
columnar-shuffle-batch-bytes
branch
from
October 14, 2026 19:26
5231565 to
09bc6c0
Compare
Contributor
Author
|
maybe @SteNicholas or @RexXiong for review when you get a chance |
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
What changes were proposed in this pull request?
Add an optional byte limit to the columnar shuffle writer. When
celeborn.columnarShuffle.batch.sizeInBytes.enabledis true,ColumnarHashBasedShuffleWriterpushes a partition's batch once it reaches eitherceleborn.columnarShuffle.batch.sizerows orceleborn.columnarShuffle.batch.sizeInBytes.thresholdestimated bytes, whichever comes first. The estimate is the sum ofUnsafeRow.getSizeInBytes()over the rows in the batch, so the column builders are unchanged.celeborn.columnarShuffle.batch.sizeInBytes.enabledfalseceleborn.columnarShuffle.batch.sizeInBytes.threshold64k, same asceleborn.client.push.buffer.max.sizeThe same change is made to the spark-3, spark-3.5 and spark-4 columnar writers.
Why are the changes needed?
The columnar writer keeps one in-memory batch per reduce partition and pushes it only after 10,000 rows. Row count is a poor proxy for memory: 10,000 rows can be a few hundred KB or hundreds of MB, depending on string widths. Spark's memory manager does not track this memory, so it cannot spill.
If a map task has fewer than 10,000 rows per partition, nothing is pushed until the task ends. That is common: 1M rows over 200 partitions is 5,000 rows each. The task's whole output then stays on the heap. The row-based hash writer instead caps each partition's buffer at
celeborn.client.push.buffer.max.size, which defaults to 64 KiB.Example: repartition 4M rows with a 2 KiB string into 200 partitions, using 4 map tasks:
Smallest driver heap that completes the job (tried 1g, 2g, 4g, 8g, 16g):
64k(default)256k1m4mAs with the row-based writer, buffered row data is roughly
partitions x threshold. This is not a hard memory cap: as before this change, the column builders pre-size their buffers forceleborn.columnarShuffle.batch.sizerows (up to 80 KB per column per partition). Sizing those buffers from the threshold could be a follow-up.Same job at a 24g heap, where every configuration fits (mean of 2 runs):
64k256k1mSmaller batches compress slightly worse, but they avoid most of the GC work. Narrow rows are barely affected: 40M rows of 64 bytes, 50,000 rows per partition per task, 4g heap:
64k256k1mThe default of
64kmatches the row-based writer's per-partition buffer size. A larger threshold trades memory for slightly smaller shuffle output.Does this PR resolve a correctness bug?
Does this PR introduce any user-facing change?
Adds the two configs above. Behavior is unchanged unless
celeborn.columnarShuffle.batch.sizeInBytes.enabledis set.How was this patch tested?
ColumnarHashBasedShuffleWriterSuiteJ#testPushBatchWhenSizeInBytesThresholdReachedto the spark-3, spark-3.5 and spark-4 columnar modules. It checks the rows in each pushed batch, with the byte limit (8, 8, 8, 6) and without it (30).build/mvn -P<profile> -pl client-spark/<module> -am test -Dtest=ColumnarHashBasedShuffleWriterSuiteJ -DwildcardSuites=noneforspark-3.3,spark-3.5andspark-4.0. All 14 tests pass in each. Maven CI doesn't run the columnar modules, so these were run locally.docs/configuration/columnar-shuffle.mdwithConfigurationSuite.local[4]with one local worker, JDK 17, on a 16 vCPU arm64 host. Spark hadassets/spark-patch/Celeborn_Columnar_Shuffle_spark3.patchapplied. On 3.5 the patch needsDataTypeUtils.fromAttributesin place ofStructType.fromAttributesto compile. Timings are from a shared machine, so treat small differences as noise.