Das Problem
Grafana Mimir speichert Metriken als Prometheus-TSDB-Blöcke im Objektspeicher. Eine API, um Serien aus diesen Blöcken zu löschen, gibt es nicht. Ist ein Labelwert mit einer E-Mail-Adresse, einem Token oder einem Kundennamen einmal geschrieben, bleibt er, bis die Retention den ganzen Block entfernt. Issue #4968, "Support deleting or rewriting series in long-term storage", ist seit Mai 2023 offen und hat 77 Reaktionen. Die Anwendungsfälle im Thread sind sensible Labelwerte, Recording Rules mit falschen Werten und falsch nachgeladene Daten. Ein älteres Issue zu einer Lösch-API wurde zugunsten von #4968 geschlossen, und ein Maintainer schrieb in einem weiteren: "Mimir currently doesn't support delete series endpoint".
In #4968 erklärt ein Maintainer, dass sie dafür das Bucket-Rewrite-Werkzeug von Thanos genutzt haben, das nur mit direktem Zugriff auf die Blöcke funktioniert. Mimir bringt Werkzeuge zum Kopieren, Auflisten, Markieren und Wiederherstellen von Blöcken mit, aber keines, das Serien umschreibt. Ein Werkzeug von Dritten habe ich nicht gefunden.
Was das Werkzeug macht
mimir-rewrite ist ein Go-Programm, das direkt auf dem Bucket arbeitet (Verzeichnis oder S3). plan lädt von jedem Block eines Tenants nur den Index und zählt, was eine Änderung betreffen würde. apply schreibt die betroffenen Blöcke neu. Drei Arten von Änderungen lassen sich kombinieren: Serien löschen, die auf einen Selektor passen, für die ganze Zeit oder in einem Zeitbereich; Prometheus-relabel_configs; und Labelwerte durch ein gesalzenes SHA-256-Präfix ersetzen, das die Serie behält und den Wert entfernt.
Löschungen nutzen direkt die Prometheus-TSDB-Bibliothek: Sie werden als Tombstones geschrieben, und der Prometheus-Compactor schreibt einen neuen Block, der die Chunks kopiert und weglässt, was die Tombstones abdecken. Beim Umbenennen wird jedes Sample unter den neuen Labels neu kodiert. Bevor etwas hochgeladen wird, berechnet das Werkzeug aus dem Originalblock, wie viele Samples jede Ausgabeserie haben muss, und vergleicht das mit dem neuen Block.
Der Mimir-spezifische Teil ist der Austausch. Der alte Block bekommt zuerst eine No-Compact-Markierung, damit der Compactor während des Umschreibens keinen Job darauf startet. Der neue Block wird mit eigener No-Compact-Markierung hochgeladen, meta.json zuletzt. Dann wird der alte Block an beiden Stellen, die Mimir nutzt (Blockverzeichnis und markers/), zum Löschen markiert, danach werden beide No-Compact-Markierungen entfernt. Mimirs Compactor ignoriert Blöcke mit Löschmarkierung sofort, sieht also nie alten und neuen Block zugleich und kann gelöschte Daten nicht zurückmischen. Die neue meta.json behält Mimirs externe Labels; haben sich Labels geändert, fällt __compactor_shard_id__ weg, weil die Serie dann nicht mehr zu diesem Shard passen muss.
Beispiel
Aus dem End-to-End-Test gegen Mimir 3.2.4, nachdem ein Block mit drei Nutzern über Mimirs Block-Upload-API hochgeladen wurde:
$ mimir-rewrite apply -bucket /data/blocks -tenant e2e-upload -delete '{user="bob@example.com"}' -yes
BLOCK FROM TO SERIES DELETE REMOVED RELABELED DROPPED ACTION
01M6ZEBBJ620SVTW3HXYQPZ017 2026-11-06T06:00Z 2026-11-06T07:59Z 4 2 2 0 0 rewrite
block 01M6ZEBBJ620SVTW3HXYQPZ017: samples 1560 -> 960, series 4 -> 2, verified
block 01M6ZEBBJ620SVTW3HXYQPZ017: uploaded replacement 01M6ZEBFP1MKPHZNQ2TBZPY0TR
block 01M6ZEBBJ620SVTW3HXYQPZ017: marked for deletion
Wie es getestet ist
Unit-Tests bauen Blöcke mit Float-, Native-Histogram- und Float-Histogram-Serien und prüfen Löschen, Umbenennen, Hashen, Kollisionen und die Reihenfolge der Bucket-Operationen. Der End-to-End-Test startet Mimir im monolithischen Modus. Ein Fall lädt einen Block über die Upload-API hoch, löscht einen Nutzer, hasht die übrigen Nutzerwerte und wartet, bis der Compactor die ersetzten Blöcke gelöscht hat. Der andere schreibt Daten per Remote Write, lässt den Ingester flushen und löscht 30 Minuten einer Serie. Jeder Schritt wird über Mimirs Query-API geprüft, und der Test schlägt fehl, wenn während des Austauschs auch nur eine Abfrage scheitert. Das CI führt das gegen Mimir 3.2.4 mit Verzeichnis-Bucket und mit S3 (SeaweedFS) aus sowie gegen Mimir 2.17.0.
Dabei fiel eine Sache auf. Mit Verzögerungen, bei denen der Store-Gateway einen markierten Block fallen ließ, bevor die Querier den Bucket-Index neu geladen hatten, schlugen Abfragen etwa 35 Sekunden lang mit einem Konsistenzfehler fehl. Mimirs Standardwerte halten die umgekehrte Reihenfolge ein, und der Test nutzt jetzt kurze Verzögerungen in dieser Reihenfolge.
Grenzen
Das Werkzeug braucht Schreibzugriff auf den Bucket. Es ist für Betreiber gedacht und keine API pro Tenant, wie sie das Issue wünscht. Unterstützt werden Verzeichnisse und S3, nicht GCS oder Azure. Daten, die noch in den Ingestern liegen, bleiben unberührt. Beim Umbenennen liegen die Serien eines Blocks im Speicher. Änderungen werden erst nach Mimirs Löschverzögerungen sichtbar, mit Standardwerten nach bis zu etwa einer Stunde. Nicht getestet: Split-and-Merge-Kompaktierung mit mehreren Shards, Out-of-Order-Blöcke und ein Compactor-Job, der beim Start des Werkzeugs schon läuft.
Der Code liegt unter github.com/Jwrede/mimir-rewrite.