Ruler: cache parsed rule files during rule sync - #16512
Conversation
|
💻 Deploy preview available (Mimir): |
|
@cursor review |
…tenants A cache miss stored and returned the same *rulefmt.RuleGroups pointer. rules.Manager.LoadGroups keeps SourceTenants aliased by reference, and federated rule evaluation later sorts that slice in place (tenant.NormalizeTenantIDs), racing with any later cache read of the same entry. Cache a defensive copy instead. Found by Cursor Bugbot: #16512 (comment)
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit d45fbec. Configure here.
Add the experimental -ruler.rule-file-parse-caching-enabled flag. When enabled, FSLoader skips rulefmt.Parse for a rule file whose exact bytes and parse options match the last successful parse, avoiding redundant YAML unmarshalling of unchanged namespace files on every tenant sync. Defaults to disabled.
…tenants A cache miss stored and returned the same *rulefmt.RuleGroups pointer. rules.Manager.LoadGroups keeps SourceTenants aliased by reference, and federated rule evaluation later sorts that slice in place (tenant.NormalizeTenantIDs), racing with any later cache read of the same entry. Cache a defensive copy instead. Found by Cursor Bugbot: #16512 (comment)
013a9e7 to
d91bd10
Compare
…tenants A cache miss stored and returned the same *rulefmt.RuleGroups pointer. rules.Manager.LoadGroups keeps SourceTenants aliased by reference, and federated rule evaluation later sorts that slice in place (tenant.NormalizeTenantIDs), racing with any later cache read of the same entry. Cache a defensive copy instead. Found by Cursor Bugbot: #16512 (comment)
10b89ae to
414c0ea
Compare
A namespace file's cache entry was never removed on rename or delete. It was only freed when the tenant's whole FSLoader was torn down. A tenant with ongoing namespace churn would accumulate one dead entry per distinct path ever seen. That growth was unbounded for the life of the tenant's manager assignment. Split the cache into two generations, cur and prev. rules.Manager calls Load at most once per path per Update pass. Seeing a path already in cur means a new pass started, so rotate. A prev hit is promoted back into cur. This keeps a stable file triggering rotation on later passes. A path that stops being loaded ages out within two passes, once prev is next overwritten. This bounds the cache at roughly 2x the live file count, regardless of total distinct paths ever used. Known gap: a tenant whose entire namespace set changes to new paths on every single pass, with no namespace ever stable across two consecutive passes, never triggers a rotation. This defeats the bound. Considered acceptable. It requires zero stable namespaces ever, not just occasional renames.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit bacb53a. Configure here.
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit bacb53a. Configure here.
Why
Profiling a production ruler found redundant YAML parsing on the rule sync path.
An unchanged namespace file gets fully re-parsed every time another namespace changes for that tenant.
What's Changed
FSLoaderBenchmark
FSLoader.Loadon an unchanged 20-group/5-rule namespace file, repeated calls, cache disabled vs enabled (benchstat, n=10):Notes
FSLoaderhas a single production call site,pkg/ruler/compat.go.It isn't shared with any other component.