Skip to content

[Dataflow Streaming] Commit size validation for multi key commits - #39473

Open
arunpandianp wants to merge 26 commits into
apache:masterfrom
arunpandianp:multikey_commit_validation
Open

[Dataflow Streaming] Commit size validation for multi key commits#39473
arunpandianp wants to merge 26 commits into
apache:masterfrom
arunpandianp:multikey_commit_validation

Conversation

@arunpandianp

Copy link
Copy Markdown
Contributor

Please add a meaningful description for your change here


Thank you for your contribution! Follow this checklist to help us incorporate your contribution quickly and easily:

  • Mention the appropriate issue in your description (for example: addresses #123), if applicable. This will automatically add a link to the pull request in the issue. If you would like the issue to automatically close on merging the pull request, comment fixes #<ISSUE NUMBER> instead.
  • Update CHANGES.md with noteworthy changes.
  • If this contribution is large, please file an Apache Individual Contributor License Agreement.

See the Contributor Guide for more tips on how to make review process smoother.

To check the build health, please visit https://github.com/apache/beam/blob/master/.test-infra/BUILD_STATUS.md

GitHub Actions Tests Status (on master branch)

Build python source distribution and wheels
Python tests
Java tests
Go tests

See CI.md for more information about GitHub Actions CI or the workflows README to see a list of phrases to trigger workflows.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@arunpandianp
arunpandianp force-pushed the multikey_commit_validation branch 2 times, most recently from 130dafe to 8553e14 Compare August 14, 2026 00:26
@arunpandianp
arunpandianp force-pushed the multikey_commit_validation branch from 8553e14 to 49db96a Compare August 14, 2026 00:50
@arunpandianp arunpandianp changed the title [wip] Multikey commit validation [Dataflow Streaming] Commit size validation for multi key commits Aug 14, 2026
@arunpandianp
arunpandianp marked this pull request as ready for review August 14, 2026 02:43
@arunpandianp

Copy link
Copy Markdown
Contributor Author

R: @scwhittle

@github-actions

Copy link
Copy Markdown
Contributor

Stopping reviewer notifications for this pull request: review requested by someone other than the bot, ceding control. If you'd like to restart, comment assign set of reviewers

}

// MultiKeyBatchingDisabled items should not be in keyGroupWorkList
checkState(!Node.isMultiKeyBatchingDisabled(firstNode.task));

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.

do we need Node. ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, because the code here is not inside Node. static import fails saying the method is private.

return;
}

// Look at budgetHandle instead of executedWorks because when intermediate work items are

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.

Comment was a little unclear at first. Maybe something like the following?

// If this is a multi-key work item, then we need to retry all of the individual work items without merging so that we can identify large commits to truncate. We determine the work items that were part of the bundle by looking at the budgethandle instead of executedWorks because validateCommitRequestSize is called when transitioning and the handle has been updated but executedWorks has not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

if (elapsedNanos >= multiKeyBundleOptions.maxKeyGroupBatchTimeNanos()) {
return true;
}
return getBytesSinked() >= multiKeyBundleOptions.maxKeyGroupBatchSinkBytes();

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.

bytessinked currently is just the output messages. There is a todo to measure state. I think that we should update the flushing of key state to add in the state bytes so that we can stop merging keys if each key is modifying state and it adds up. Then we will be less likely to need to truncate since the sinkbytes limit is lower than the max limit.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is a good idea to stop merging when we hit a limit including state updates. We can accumulate the individual commit size from flushStateInternal and compare that against a threshold. Will send a separate change for that.

We flush key state per key and truncation is only based on individual key commit size, so I'm not sure if counting the state updates will reduce truncations.

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.

Maybe my terminology was confusing, but I was thinking of the case where each key is flushing to state that we might build up too large a commit to apply. Then we have to retry all of the bundles locally without merging instead of just stopping earlier. If we were counting the state bytes we could just stop before we built up such a large commit and wouldn't have to retry.

Node(Runnable task) {
this.task = task;
if (task instanceof QueuedWork) {
if (task instanceof QueuedWork && !isMultiKeyBatchingDisabled(task)) {

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.

could just be
if (!isMultiKeyBatchingDisabled(task)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

computationState, handle.getWorkBatch(), computationId, systemName, work, t);
} finally {
List<Work> processedWorkBatch = workBatch != null ? workBatch : ImmutableList.of(work);
List<Work> processedWorkBatch = workBatch != null ? workBatch : handle.getWorkBatch();

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.

is it always correct to use the handle batch? should we just use that and possibly remove from ExecuteWorkResult as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good idea, done and removed executedWorks. I added handle.getWorkBatch after adding executedWorks and didn't think about it to replace executedWorks

.build());
}

Windmill.MultiKeyWorkItemCommitRequest multiKeyCommitRequest = multiKeyBuilder.build();

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.

does this possibly throw and thus is done earlier now? If so add a comment, if not maybe revert.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

reverted.

if (elapsedNanos >= multiKeyBundleOptions.maxKeyGroupBatchTimeNanos()) {
return true;
}
return getBytesSinked() >= multiKeyBundleOptions.maxKeyGroupBatchSinkBytes();

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.

Maybe my terminology was confusing, but I was thinking of the case where each key is flushing to state that we might build up too large a commit to apply. Then we have to retry all of the bundles locally without merging instead of just stopping earlier. If we were counting the state bytes we could just stop before we built up such a large commit and wouldn't have to retry.

StreamingDataflowWorker worker =
makeWorker(
defaultWorkerParams(
"--experiments=unstable_enable_multi_key_bundle,windmill_max_key_group_batch_time_ms=5000",

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.

larger timeout just so it isn't possibly flaky?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

List<ParallelInstruction> instructions =
Arrays.asList(
makeSourceInstruction(kvCoder),
makeDoFnInstruction(new FixedSizeCommitFn(500), 0, kvCoder),

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.

maybe have a dofn that you can see that the work is re-executed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done. Updated tests to use a DoFn writing to state instead of using productions. Added a todo to add tests using productions. Need to send a WindmillSink change to flush productions in finishKey.

Windmill.Uint128Proto keyGroup =
Windmill.Uint128Proto.newBuilder().setHigh(1).setLow(2).build();

Work work1 =

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.

I only see one work in this test so it doesn't seem like it is necessarily stopping because the batching is disabled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated and renamed the test.

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.

does this need to use the handle works as well? Can we get rid of executedWorks?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good idea, removed executedWorks

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants