Skip to content

performance: add opt-in debounce for resource updates - #9773

Closed
zhaohuabing wants to merge 7 commits into
envoyproxy:mainfrom
zhaohuabing:xds-update-debounce
Closed

performance: add opt-in debounce for resource updates#9773
zhaohuabing wants to merge 7 commits into
envoyproxy:mainfrom
zhaohuabing:xds-update-debounce

Conversation

@zhaohuabing

@zhaohuabing zhaohuabing commented Aug 18, 2026

Copy link
Copy Markdown
Member

Envoy Gateway coalesces updates today only by backpressure — the watchable library merges stores that pile up while a consumer is busy — plus last-write-wins within a single snapshot. Neither is time-based, so when translation is fast but resources are churning, each change costs its own translation and its own push to Envoy, even though only the resulting state matters.

This PR adds a time-based debounce, configured via the top-level debounce field in the EnvoyGateway config and disabled by default. A pending batch is flushed once no new change has arrived for debounce.after (default 100ms), or after debounce.max (default 10s) when changes keep arriving, so isolated changes still propagate promptly while sustained churn has a bounded push rate.

The debounce sits on the gateway-api runner's subscription, ahead of TranslateToIR, so it collapses churn before both the Gateway API and the xDS translation.

Measured

Scaling a backend Deployment 180 times between 1 and 20 replicas, 100ms apart, against a single proxy:

disabled enabled (defaults)
provider publishes 277 296
snapshots created 276 154
snapshot updates pushed 276 154
pushes per publish 0.996 0.520

A 44% raw reduction in pushes to Envoy, or 48% after normalizing for the slightly higher input volume. watchable_coalesced_updates_total reported 142, exactly the 296 − 154 difference. Mean hold time was 159ms, and every flush was reason="quiet", so max was never reached.

Two caveats on reading that. The churn interval here (100ms) equals the default after, which is close to the least favourable spacing for a debouncer — each change tends to arrive just as the quiet period expires, and the average batch was only 1.92 updates. Faster churn coalesces more; churn slower than after coalesces nothing. And this ran against a single Envoy, while xds_snapshot_update_total is counted per node, so absolute savings scale with fleet size.

Churn script: https://gist.github.com/zhaohuabing/33a57e7b6fd3126c17001c3208d288b2

Observability

The watchable_subscribe_duration_seconds buckets topped out at 10s, which hid the tail where a single translation takes tens of seconds; they now extend to 120s, keeping the existing boundaries so the change is additive. New metrics watchable_debounce_pending, watchable_debounce_flush_total and watchable_debounce_delay_seconds cover the debouncer, and watchable_coalesced_updates_total counts the updates dropped by coalescing — previously visible only in an info-level log line, which is of no use on a control plane configured to log at error.

Note that watchable_depth is always 0, because snapshots are delivered over an unbuffered channel. That is pre-existing and left alone here, but documented so it is not mistaken for a healthy queue.

Alternative

Debouncing the kubernetes provider reconcile - it avoids churns at the source, but may delay Gateway status update and won't hanlde other providers.

@netlify

netlify Bot commented Aug 18, 2026

Copy link
Copy Markdown

Deploy Preview for cerulean-figolla-1f9435 ready!

Name Link
🔨 Latest commit d4925aa
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/6a957a32593bbd00081de24d
😎 Deploy Preview https://deploy-preview-9773--cerulean-figolla-1f9435.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.40000% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.32%. Comparing base (06e3790) to head (ba0959a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/gatewayapi/runner/runner.go 25.80% 21 Missing and 2 partials ⚠️
api/v1alpha1/validation/envoygateway_validate.go 91.66% 1 Missing and 1 partial ⚠️
internal/message/watchutil.go 96.82% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9773      +/-   ##
==========================================
+ Coverage   76.30%   76.32%   +0.02%     
==========================================
  Files         261      261              
  Lines       44351    44467     +116     
==========================================
+ Hits        33842    33940      +98     
- Misses       8271     8288      +17     
- Partials     2238     2239       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 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.

@zhaohuabing

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8975c30dfd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread release-notes/current/performance_improvements/9773-xds-update-debounce.md Outdated
Merge bursts of resource changes into a single translation instead of
translating and pushing each one, bounding how often configuration is
pushed to Envoy under heavy EndpointSlice churn. Configured via
spec.debounce and disabled by default.

Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com>
Signed-off-by: Huabing (Robin) Zhao <huabing@tetrate.io>
Give the debounce-aware entry point a *DebounceOptions parameter so callers
can pass nil, and keep HandleSubscription as a thin wrapper over it. The
gateway-api call site then needs no branch and keeps its handler inline,
and no other caller changes.

Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com>
Signed-off-by: Huabing (Robin) Zhao <huabing@tetrate.io>
Describe the cost of undebounced updates without naming a particular
resource type or asserting how translation is implemented, and drop a
comment that only restated the code.

Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com>
Signed-off-by: Huabing (Robin) Zhao <huabing@tetrate.io>
Add watchable_coalesced_updates_total so the updates dropped by coalescing
can be observed at any log level, not only where the existing info log is
enabled. Name the snapshot channel for what it carries, drop a redundant
Stop before Reset, and stop recording watchable_depth on the debounced
path, where it is always zero.

Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com>
Signed-off-by: Huabing (Robin) Zhao <huabing@tetrate.io>
@zhaohuabing
zhaohuabing marked this pull request as ready for review August 18, 2026 09:37
@zhaohuabing
zhaohuabing requested a review from a team as a code owner August 18, 2026 09:37
Follow how xdsServer durations are handled: the validation package owns the
rules, and the runner parses the strings where it uses them. This drops
DebounceSettings, which was the only method in the EnvoyGateway helpers that
validated its input and returned an error.

Signed-off-by: Huabing (Robin) Zhao <zhaohuabing@gmail.com>
Signed-off-by: Huabing (Robin) Zhao <huabing@tetrate.io>
Signed-off-by: Huabing (Robin) Zhao <huabing@tetrate.io>
@zhaohuabing zhaohuabing changed the title add opt-in debounce for resource updates performance: add opt-in debounce for resource updates Aug 20, 2026
@zhaohuabing
zhaohuabing marked this pull request as draft August 21, 2026 03:49
# Conflicts:
#	internal/message/metrics.go
#	internal/message/watchutil.go
@zhaohuabing zhaohuabing closed this Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant