Skip to content

[INC-1227] dl/translation: fix busy loop under coordinator backpressure - #31419

Merged
andrwng merged 1 commit into
redpanda-data:devfrom
andrwng:iceberg-backpressure
Aug 6, 2026
Merged

[INC-1227] dl/translation: fix busy loop under coordinator backpressure#31419
andrwng merged 1 commit into
redpanda-data:devfrom
andrwng:iceberg-backpressure

Conversation

@andrwng

@andrwng andrwng commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The translation loop treated a backpressured fetch as a successful iteration and canceled its retry jitter, so backpressured translators re-polled the coordinator as fast as the fetch RPC completed. This added noticeable CPU churn in some clusters with existing backpressure.

This commit routes backpressured iterations through the same jittered sleep as a failed fetch; a requested finish still proceeds.

This also adds a ducktape test that bounds the cumulative backoff counter, which records a spin no matter when it is sampled. Without the change, this test saw 1.1 cores of the datalake scheduling group runtime, vs 0.001 core with this commit (and 1.6M loop iterations vs 260).

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v26.2.x
  • v26.1.x
  • v25.3.x

Release Notes

Bug Fixes

  • Fixes an issue where backpressure from the Iceberg coordinator would cause high CPU load on the translators.

Copilot AI review requested due to automatic review settings August 4, 2026 22:07

Copilot AI 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.

Pull request overview

Fixes a translator busy-loop when the Iceberg coordinator applies backpressure by ensuring backpressured iterations take the same jittered sleep path as failed fetches, reducing CPU churn. Adds unit/integration coverage to detect regressions in backpressure pacing.

Changes:

  • Mark coordinator backpressure explicitly in translation_offsets and route backpressured iterations through the jittered retry path.
  • Add a C++ unit test to assert backpressured coordinator polling is paced (not spinning).
  • Extend the ducktape backpressure test to log scheduling-group CPU and bound backoff-loop iterations.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
tests/rptest/tests/datalake/coordinator_backpressure_test.py Adds CPU visibility helper and a regression assertion bounding backoff iterations under coordinator backpressure.
src/v/datalake/translation/tests/partition_translator_tests.cc Adds a unit test to ensure backpressure handling is paced (limits coordinator polling rate).
src/v/datalake/translation/partition_translator.h Extends translation_offsets with a backpressure flag to propagate coordinator load-shedding state.
src/v/datalake/translation/partition_translator.cc Sets the new backpressure flag on fetch and applies jittered pacing when backpressured.

nodes=self.redpanda.nodes,
metrics_endpoint=MetricsEndpoint.METRICS,
)
assert samples is not None
err_msg="pending/translated file counts never stabilized under backpressure",
)

# Regresison check for a case where translation would spin and
Comment on lines +478 to 484
// A backpressured iteration takes the jittered retry path like a
// failed fetch, rather than immediately polling the coordinator
// again. A requested finish still proceeds below.
if ((!offsets || offsets->backpressure) && !finish_now) {
continue;
}
if (offsets->next_translation_begin_offset && !finish_now) {

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 don't think you're correct here, robot.

@andrwng
andrwng force-pushed the iceberg-backpressure branch from 34e7ac1 to e8d93c0 Compare August 4, 2026 22:39
@andrwng andrwng changed the title dl/translation: fix busy loop under coordinator backpressure [INC-1227] dl/translation: fix busy loop under coordinator backpressure Aug 4, 2026
@andrwng
andrwng force-pushed the iceberg-backpressure branch from e8d93c0 to fe90050 Compare August 4, 2026 22:54
@vbotbuildovich

vbotbuildovich commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

CI test results

test results on build#88204
test_status test_class test_method test_arguments test_kind job_url passed reason test_history
FLAKY(PASS) DataMigrationsApiTest test_migrated_topic_data_integrity {"params": {"cancellation": {"dir": "in", "stage": "preparing"}, "include_groups": true, "transfer_leadership": true, "use_alias": true}} integration https://buildkite.com/redpanda/redpanda/builds/88204#019fcf02-ae5e-46a8-a8db-44ae956a0a5a 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0000, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=DataMigrationsApiTest&test_method=test_migrated_topic_data_integrity
FLAKY(PASS) NodeWiseRecoveryTest test_recovery_local_data_missing {"wait_for_final_manifest_uploads": true} integration https://buildkite.com/redpanda/redpanda/builds/88204#019fcf02-02d8-4609-badf-e5a0a98f2f62 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0246, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=NodeWiseRecoveryTest&test_method=test_recovery_local_data_missing
test results on build#88292
test_status test_class test_method test_arguments test_kind job_url passed reason test_history
FLAKY(PASS) STSRoleFetchTests test_write null integration https://buildkite.com/redpanda/redpanda/builds/88292#019fd3fd-4479-475b-8b78-4d7bffb85bbf 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0000, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=STSRoleFetchTests&test_method=test_write

wdberkeley
wdberkeley previously approved these changes Aug 5, 2026

@wdberkeley wdberkeley 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.

LGTM but the ducktape test measuring CPU usage seems unnecessary and overwrought, perhaps fragile?

@andrwng

andrwng commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

LGTM but the ducktape test measuring CPU usage seems unnecessary and overwrought, perhaps fragile?

Yea it is a bit much here. In general I do think high CPU load is something worth checking for in tests, but I don't think we've established a good general check for it. Probably overkill here and not sustainable for a regression test. Removed

@andrwng
andrwng requested a review from wdberkeley August 5, 2026 21:57
The translation loop treated a backpressured fetch as a successful
iteration and canceled its retry jitter, so backpressured translators
re-polled the coordinator as fast as the fetch RPC completed. This added
noticeable CPU churn in some clusters with existing backpressure.

This commit routes backpressured iterations through the same jittered
sleep as a failed fetch; a requested finish still proceeds.
@andrwng
andrwng force-pushed the iceberg-backpressure branch from c29fad7 to 837a794 Compare August 5, 2026 21:58
Comment on lines 475 to +482
if (finish_now) {
vlog(_logger.debug, "Requested for immediate finish");
}
if (!offsets && !finish_now) {
if (!offsets) {
// Without reconciled offsets there is nothing to translate or
// finish against.
continue;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm sure I'm missing something, but it reads buggy that finish_now isn't the highest priority check here, allowing other conditions to take precedence in continuing in the loop

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.

The issue is that there isn't a well thought through way to stop work without information from the coordinator, because finishing typically entails sending completed work to the coordinator.

There's probably a different fix that entails discarding the data we have, but it seems a bit more involved to ensure correctness. At the very least avoiding a null dereference seems like an easier win

@andrwng
andrwng enabled auto-merge August 6, 2026 21:58
@andrwng
andrwng merged commit e93b13e into redpanda-data:dev Aug 6, 2026
19 checks passed
@andrwng

andrwng commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

/backport v26.2.x

@andrwng

andrwng commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

/backport v26.1.x

@andrwng

andrwng commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

/backport v25.3.x

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.

5 participants