Skip to content

[Refactor] Add TTL / version-stamp to MatchDataCache to guard against stale cached match results #7651

Closed

Description

@Aias00

Background

PR #7055 optimized the positive cache reuse path in AbstractShenyuPlugin (moved defaultMatchSelector/defaultMatchRule into the null-cache branch so a reused cached MatchData takes effect). This fixes the reuse logic, but does not address a deeper safety gap in the underlying cache: the cached match result has no time-based expiry, so it is not guaranteed to be safe to reuse when a data-sync event is missed.

Root cause analysis

MatchDataCache (shenyu-plugin/shenyu-plugin-base) builds an L1 WindowTinyLFUMap keyed by (pluginName, path) plus an L2 trie. The L1 map is constructed with the three-arg form:

new WindowTinyLFUMap<>(capacity, maxSize, false)
  • The boolean false only disables sampling-based admission; there is no expireAfterWrite.
  • The four-arg constructor WindowTinyLFUMap(capacity, maxSize, false, expireAfterWrite) exists but is unused.
  • Cache entries are written only when all conditions are URI_CONDITION_TYPE and matchRestful is false.
  • Invalidation is fully event-driven: CommonPluginDataSubscriber calls removeSelectorData / removeRuleData / cleanXxx on selector/rule/plugin add/update/delete, plus LocalPluginController local mode.

Risk

Because eviction is size-only, if a data-sync event (websocket / nacos / zookeeper notification) is dropped, delayed, or processed out of order, a stale selectorData/ruleData can remain in the cache indefinitely — there is no time-based self-healing. Under selector/rule churn this can cause:

  • Wrong selector/rule matched → incorrect routing / plugin skip / wrong upstream chosen.
  • Negative-cache sentinels (removeEmptyXxx) similarly never expire.

Proposal

Add a bounded TTL to the cached match result:

  1. Use the existing four-arg WindowTinyLFUMap(capacity, maxSize, false, expireAfterWrite) with a short window (e.g. 30–60s), OR
  2. Embed a data-version / epoch stamp in the cache key/value and invalidate when the plugin data version changes, OR
  3. Both: TTL as a safety net + version stamp for precise invalidation.

The TTL should be configurable (e.g. via shenyu.match.cache.ttl) with a sensible default, and documented as a trade-off between reuse hit-rate and staleness window.

Acceptance criteria

  • Stale entries are auto-purged after the TTL even if no data-sync event arrives.
  • Negative-cache sentinels respect the same TTL.
  • TTL is configurable with a safe default; hit-rate regression verified by existing match tests.
  • No behavior change for the normal (event-driven) invalidation path.

Related: #7055

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions