Skip to content

mimir-mixin: fix alert defs for compartmentalized deployments - #16289

Draft
pitasi wants to merge 12 commits into
mainfrom
anto/fix-alerts-compartments
Draft

mimir-mixin: fix alert defs for compartmentalized deployments#16289
pitasi wants to merge 12 commits into
mainfrom
anto/fix-alerts-compartments

Conversation

@pitasi

@pitasi pitasi commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Fix alerts definitions for compartments, in a backwards compatible way (= the definition should work both on non-compartmentalized and compartmentalized deployments).

@pitasi pitasi added the changelog-not-needed PRs that don't need a CHANGELOG.md entry label Aug 3, 2026
@pitasi
pitasi force-pushed the anto/fix-alerts-compartments branch from 7d63a05 to 9732e6e Compare August 3, 2026 15:29
@pitasi pitasi changed the title Anto/fix alerts compartments mimir-mixin: fix alert defs for compartmentalized deployments Aug 4, 2026
pitasi and others added 12 commits August 11, 2026 10:42
Compartments scope workload and ring names with a "-rc-<id>" suffix but add no
label to any metric, because a per-compartment label would change a metric's
label set and collide with the same metric registered by another component in
the same process. Alerts that must not mix compartments therefore have to parse
the compartment out of an existing label.

Add a single helper for that, so the regex lives in one place instead of being
repeated by every alert that needs it. No alert uses it yet, so the compiled
mixin is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The compiled mixin is generated with compartments disabled, so nothing exercised
the compartment code paths and a whole class of breakage went unnoticed: rules
that hardcode a ring name, or that group workloads by stripping a trailing
"-zone-<x>", stop working once compartments append "-rc-<id>" to those names.

Add a test variant with compartments enabled and assert the invariants that
generated alerts and rules must hold. The compactor scheduler is enabled too, as
it is deployed per read compartment.

Four assertions fail on purpose right now, one per bug they pin down:
"ingester-partitions" ring matcher in alerts, and zone-only workload grouping in
alerts, rules and the rollout progress dashboard. The following commits fix them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MimirFewerIngestersConsumingThanActivePartitions could not fire at all when
compartments are enabled: each read compartment registers its own partition ring,
named "ingester-partitions-rc-<id>", so the equality matcher on the bare ring name
selected nothing and the left hand side of the comparison was always empty.

Matching the suffixed name is not enough on its own. Partition IDs are derived
from the ingester ordinal and therefore restart from 0 in every compartment, so
comparing the largest compartment's partition count against the union of all the
compartments' (colliding) partition IDs hides a shortfall: two compartments of
two partitions each look like two partitions with four consumers. Both sides now
carry a read_compartment label and are compared per compartment.

A compartment that loses every consumer has no series on the right hand side, and
vector matching would silently drop it from the comparison, so the right hand side
defaults to zero consumers for every compartment the ring knows about. That case
was also undetected without compartments, where it needed every ingester in the
namespace to stop consuming; with compartments losing one compartment is enough,
which is exactly what this alert should catch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every read compartment keeps the blocks of every tenant in its own bucket, with
its own compactors maintaining that bucket's index, so a tenant reports one
cortex_bucket_index_last_successful_update_timestamp_seconds per compartment.
MimirBucketIndexNotUpdated aggregated those with "min", which keeps the freshest
timestamp, so a compartment whose bucket index had gone stale was masked by any
healthy compartment and queriers would start failing without a page.

Group by the compartment as well, and name it in the alert message so it is clear
which bucket to look at.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each read compartment runs its own compactor scheduler over its own bucket, but
MimirCompactorSchedulerNotCompletingJobs summed the completed jobs of every
scheduler in the namespace before comparing to zero, so one scheduler completing
jobs was enough to hide another that had completely stalled.

Count the completed jobs per compartment instead, and keep the compartment on
MimirCompactorSchedulerRepeatedJobFailure too, which fired without saying which
scheduler was failing.

These alerts are only generated when the compactor scheduler is enabled, so the
compiled mixin is unchanged; the compartments mixin test enables it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MimirIngesterInstanceHasNoTenants only fires if the cell holds more series than
continuous testing alone would produce. On ingest storage that total is computed
by deduplicating the zone replicas of a partition, which hold the same series,
using the ingester ordinal as the identity.

The ordinal restarts from 0 in every read compartment, so ingesters of different
compartments, which hold different partitions and therefore different series,
were deduplicated as if they were replicas of each other. The total came out
roughly divided by the number of compartments and could stay under the threshold,
suppressing the alert.

Include the compartment in the identity so only genuine zone replicas are
deduplicated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MimirRolloutStuck derives a rollout_group by stripping an optional trailing
"-zone-<x>" from the workload name. label_replace anchors its regex, so with
compartments the zone is no longer at the end ("ingester-zone-a-rc-0") and nothing
is stripped: every zone becomes a rollout group of its own.

That fires spuriously on every rollout longer than 30 minutes. The rollout-operator
updates one zone of a group at a time, so a zone waiting its turn sits at zero
updated replicas with nothing changing, which is indistinguishable from a stuck
rollout once it is looked at in isolation. Grouped correctly, the progress of the
zone being updated keeps the alert quiet.

Match the compartment suffix explicitly, so zones group into the rollout group the
rollout-operator actually manages ("ingester-rc-0"), which is also the value it
reports on rollout_operator_last_successful_group_reconcile_timestamp_seconds, so
MimirRolloutStuck and RolloutOperatorNotReconciling can be correlated again.

The regex lives in the config because the scaling rules and the rollout progress
dashboard group workloads the same way and are fixed next. Nothing changes without
compartments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two MimirIngesterTSDBWALCorrupted alerts tell apart a deployment spread over
several zones, where corruption reaching more than one zone risks unrecoverable
data loss, from a single-zone one, where any corruption does. Both inferred the
number of zones from the number of distinct ingester jobs.

With compartments each zone has one job per compartment ("ingester-zone-a-rc-0"),
which breaks that inference in both directions: a single-zone cell with two
compartments looks like it has two zones, so the single-zone variant can never
fire; and two corrupted ingesters in the same zone but different compartments look
like two corrupted zones, so the multi-zone critical fires even though every
compartment replicates across zones on its own and has only lost one replica.

Extract the zone from the job name and count zones instead. Without compartments
the job name is the zone, so nothing changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The scaling recording rules group a workload with the other workloads it is scaled
together with by stripping a trailing "-zone-<x>", in eight places across
actual_replicas, the CPU and memory usage and the resource requests. As in
MimirRolloutStuck, that regex strips nothing once compartments move the zone away
from the end of the name, so every zone of every compartment was reported as a
scaling target of its own rather than one entry per compartment.

Reuse the shared workload group regex, which keeps the current behaviour without
compartments and groups the zones of a compartment together with them. All the
rules that feed cpu_required_replicas_count and memory_required_replicas_count are
changed together, so they keep matching each other.

The baremetal variants don't group by zone and are left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The scaling rules that size a component for a whole namespace, by sample rate or
active series, label their result with the bare component name. The Scaling
dashboard joins those to the actual replica count on the "deployment" label, which
with compartments is only ever recorded per compartment ("ingester-rc-0"), so the
join matched nothing and the sample_rate, active_series and *_limits rows silently
disappeared from the dashboard.

Record the total across a component's compartments next to the per-compartment
counts, so both kinds of rule find a counterpart: the namespace-wide ones match the
total, and the CPU and memory ones, which are derived per compartment, keep
matching the per-compartment counts.

Without compartments the selector matches nothing and no series is recorded, so
nothing changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Rollout Progress dashboard folds Deployments and StatefulSets into a "workload"
label and then strips a trailing "-zone-<x>" to show one row per group of workloads
rolled out together. With compartments the zone is no longer at the end of the name,
so nothing was stripped and the dashboard listed every zone of every compartment
separately instead of one row per compartment.

Reuse the shared workload group regex, the same one MimirRolloutStuck and the
scaling rules use, so the dashboard rows line up with the rollout groups the
rollout-operator manages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Regenerates the alerts, recording rules and dashboards embedded in the Helm chart's
metamonitoring output, after the compartment fixes in the preceding commits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@pitasi
pitasi force-pushed the anto/fix-alerts-compartments branch from 9732e6e to adb4853 Compare August 11, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog-not-needed PRs that don't need a CHANGELOG.md entry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant