[2.3] fix: cache strict-validation verdicts by config content#14242
Merged
davidjumani merged 1 commit intoJun 12, 2026
Merged
Conversation
Signed-off-by: David L. Chandler <[email protected]>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR reduces strict-validation bottlenecks by memoizing envoy --mode validate verdicts based on the bootstrap config content hash, preventing redundant forks across per-client fan-out and recomputes while preserving identical validation outcomes.
Changes:
- Added an LRU + singleflight–backed caching
Validatorthat caches only deterministic outcomes (success andErrInvalidXDS) keyed by a SHA-256 content hash. - Introduced
KGW_VALIDATOR_MODE(CACHE default | BINARY) andKGW_VALIDATOR_CACHE_SIZEsettings and wired validator construction throughpkg/validatorin kgateway setup. - Reduced strict RDS validation calls to 1 invocation for valid routes (2 only for invalid routes requiring matcher/action disambiguation), plus added targeted tests/benchmarks.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/validator/validator.go | Adds SHA-256 bootstrap hashing helper to support content-based memoization. |
| pkg/validator/cache.go | Implements caching validator with LRU storage and singleflight miss coalescing. |
| pkg/validator/cache_test.go | Adds unit tests for cache hit/miss, eviction, invalid-verdict caching, and singleflight collapse. |
| pkg/validator/factory.go | Adds settings-driven validator constructor (CACHE vs BINARY). |
| pkg/validator/factory_test.go | Tests validator factory wiring and fallback behavior. |
| pkg/validator/validator_bench_test.go | Benchmarks validator mode overhead and cache behavior (stubbed and optional real envoy). |
| api/settings/settings.go | Adds ValidatorMode/ValidatorCacheSize settings and env decoding. |
| api/settings/settings_test.go | Extends settings env var coverage for new validator settings. |
| pkg/kgateway/setup/setup.go | Wires setup default validator creation through the settings-driven factory. |
| pkg/kgateway/translator/irtranslator/validate.go | Optimizes strict route validation to a single full validation on success; disambiguates only on failure. |
| pkg/kgateway/translator/irtranslator/validate_test.go | Tests strict-mode call counts and error attribution (route vs matcher). |
| pkg/kgateway/translator/irtranslator/backend_validation_test.go | Adds integration coverage that strict cluster validation is cached by content and transient errors aren’t cached. |
| pkg/kgateway/proxy_syncer/perclient_bench_test.go | Adds benchmark modeling per-client connect-event drain improvements with caching. |
| go.mod | Promotes github.com/hashicorp/golang-lru/v2 to a direct dependency. |
| hack/utils/oss_compliance/osa_included.md | Records included OSS dependency/license for golang-lru/v2. |
andy-fong
approved these changes
Jun 12, 2026
chandler-solo
added a commit
to chandler-solo/kgateway
that referenced
this pull request
Jun 15, 2026
Performance fix; forward port of kgateway-dev#14242 Ref kgateway-dev#14184 Signed-off-by: David L. Chandler <[email protected]>
This was referenced Jun 15, 2026
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.
Description
Refs #14184.
A fix for the per-client xDS pipeline: the cost amplifier that turns input churn into queue backlog.
Content-hash verdict cache for strict validation
Under
KGW_VALIDATION_MODE=STRICT, every translated cluster is validated by forkingenvoy --mode validate(~200–500ms per call). Per-client translation runs once per(backend, client) pair and re-runs on every recompute — all serialized on a single KRT queue
goroutine. At field scale (hundreds of backends, several connected clients) one client
connecting costs thousands of serialized forks; the queue falls minutes behind, and the
snapshot consistency gates — which check per-client rows for presence — evaluate against
mid-drain state and defer publication. The visible symptom is the issue's:
defer building snapshot until all referenced clusters are readylisting clusters that existand are healthy. They were queued, not missing. Worse, a gateway pod that crashloops because
its first snapshot never arrives reconnects as a brand-new client and retriggers the full
fan-out — the backlog feeds itself.
A validation verdict is a pure function of the config bytes, so this PR wraps the binary
validator with an LRU cache keyed on the SHA-256 of the marshalled bootstrap:
ErrInvalidXDS); transient failures(exec errors, context cancellation) are never cached. Cached invalid verdicts keep the inner
error text verbatim and still satisfy
errors.Is(err, ErrInvalidXDS).KGW_VALIDATOR_CACHE_SIZE); entries are a32-byte hash plus a verdict — the config itself is never stored — so steady state is well
under 1 MB. Eviction is plain LRU.
Cluster config content is identical across clients and recomputes in the overwhelmingly common
case, so the expensive forks collapse even though each (backend, client) pair still translates
independently.
KGW_VALIDATOR_MODEselectsCACHE(default) orBINARY(the previousbehavior — a one-env-var rollback). Memoization cannot change validation outcomes, only skip
redundant invocations, which is why CACHE is a safe default.
Measured (in-repo benchmarks, 2ms stubbed validation; the real fork costs 100–250x more):
Change Type
/kind fix
Changelog
Additional Notes
pkg/validatorbehind the existingValidatorinterface; the translatoris unchanged apart from the injected implementation.
deferrals long; that one bounds the wait when deferrals happen anyway. Either stands alone.
call under 16 concurrent misses). Benchmarks committed in
pkg/validator/validator_bench_test.goand
pkg/kgateway/proxy_syncer/perclient_bench_test.go.