Redis Keyspace verstehen: Lösch- und Inspektionsbefehle

Nutzen Sie die Leistungsfähigkeit des Redis-Keyspace-Managements mit diesem umfassenden Leitfaden. Lernen Sie, Ihre Daten sicher mit `SCAN` zu inspizieren (und warum Sie `KEYS` in der Produktion vermeiden sollten) und Schlüssel effizient mit `DEL` und dem nicht blockierenden `UNLINK` zu löschen. Verstehen Sie die destruktive Natur von `FLUSHDB` und `FLUSHALL` und entdecken Sie Best Practices für die Aufrechterhaltung einer gesunden, leistungsstarken Redis-Instanz.

Redis Keyspace verstehen: Lösch- und Inspektionsbefehle

Der Redis-Keyspace ist einfach die Menge der Schlüssel in der aktuell ausgewählten Datenbank, aber die Art und Weise, wie Sie diese Schlüssel inspizieren und löschen, kann entscheiden, ob eine Bereinigung langweilig ist oder ob Ihre Anwendung mitten im Verkehr ins Stocken gerät.

Die meisten Teams lernen dies auf die harte Tour. Jemand muss session:*-Schlüssel aus einem Staging-Cache löschen, führt KEYS session:* aus, sieht die Liste und versucht dann dieselbe Gewohnheit in der Produktion. Bei einer winzigen Datenbank fühlt sich das in Ordnung an. Bei einer stark ausgelasteten Instanz mit Millionen von Schlüsseln kann der Befehl den Server lange genug blockieren, damit sich nicht zusammenhängende Anfragen dahinter anstellen. Redis verarbeitet Befehle sehr schnell, aber ein Befehl, der den gesamten Keyspace durchläuft, muss die Arbeit trotzdem erledigen.

Denken Sie bei alltäglichen Operationen in zwei getrennten Schritten: Finden Sie Schlüssel sicher, dann löschen Sie sie sicher. Behandeln Sie die Schlüsselinspektion nicht als harmloses Lesen. Ein Lesebefehl kann trotzdem teuer sein.

Beginnen Sie mit der Datenbank, die Sie wirklich verwenden

Bevor Sie etwas löschen, bestätigen Sie den Endpunkt und die logische Datenbank.

redis-cli -h redis.example.internal -p 6379 INFO keyspace

Die Ausgabe sieht so aus:

# Keyspace
db0:keys=154233,expires=129900,avg_ttl=2851412
db2:keys=32,expires=32,avg_ttl=60000

Das sagt Ihnen, welche logischen Datenbanken Schlüssel enthalten. Viele Redis-Bereitstellungen verwenden nur Datenbank 0. Redis Cluster unterstützt nur Datenbank 0, daher verdienen FLUSHDB und FLUSHALL dort besondere Aufmerksamkeit, da das übliche mentale Modell der "ausgewählten Datenbank" nicht auf die gleiche Weise nützlich ist.

Wenn Ihre Anwendung nummerierte Datenbanken auf einem eigenständigen Redis verwendet, wählen Sie die richtige explizit aus:

redis-cli -n 2 DBSIZE

DBSIZE gibt die Anzahl der Schlüssel in der ausgewählten Datenbank zurück. Es zeigt keine Namen und ersetzt keinen Inspektionsdurchlauf, aber es ist eine gute Plausibilitätsprüfung vor und nach der Bereinigung.

Verwenden Sie KEYS nur, wenn der Keyspace klein und entbehrlich ist

KEYS pattern gibt jeden Schlüssel zurück, der einem glob-artigen Muster entspricht:

KEYS user:*
KEYS cache:product:???
KEYS *

Die Musterregeln sind praktisch: * entspricht einer beliebigen Sequenz, ? entspricht einem Zeichen und Klammerbereiche wie [0-9] entsprechen einem Zeichen aus dem Bereich.

Das Problem ist nicht die Korrektheit. Das Problem ist, dass KEYS den gesamten Keyspace in einem Befehl scannt. Auf einem lokalen Entwicklungs-Redis mit ein paar hundert Schlüsseln ist das praktisch. Auf einem gemeinsam genutzten Cache kann es für jeden anderen Client Latenz hinzufügen, während Redis damit beschäftigt ist, das Ergebnis zu produzieren. Der Befehl ist als Keyspace-Befehl mit linearer Komplexität dokumentiert, daher sollte er nicht Teil normaler Produktionsbereinigungsskripte sein.

Ich verwende KEYS immer noch an zwei Stellen:

  • Ein Wegwerf-Local-Redis beim Schreiben von Tests.
  • Eine kleine Staging-Datenbank, bei der ich bereits DBSIZE überprüft habe und weiß, dass der Befehl mich nicht überraschen kann.

Überall sonst verwenden Sie SCAN.

Verwenden Sie SCAN für die Produktionsinspektion

SCAN ist cursor-basiert:

SCAN 0 MATCH user:* COUNT 100

Redis gibt zwei Dinge zurück: den nächsten Cursor und einen Batch von Schlüsseln. Beginnen Sie bei Cursor 0. Scannen Sie mit dem zurückgegebenen Cursor weiter. Stoppen Sie, wenn Redis wieder Cursor 0 zurückgibt.

1) "24576"
2) 1) "user:100"
   2) "user:101"

COUNT ist ein Hinweis, kein Versprechen. Redis kann mehr Schlüssel, weniger Schlüssel oder sogar keine Schlüssel für eine bestimmte Iteration zurückgeben. MATCH filtert, was zurückkommt, aber Redis durchläuft trotzdem den Keyspace. Ein enges Muster ist nützlich, um die Client-Arbeit zu reduzieren, aber es macht nicht magisch jeden Scan kostenlos.

Für Shell-Arbeiten bevorzugen Sie redis-cli --scan, weil es die Cursor-Schleife verbirgt:

redis-cli --scan --pattern 'session:*'

Um passende Schlüssel zu zählen, ohne alle auszugeben:

redis-cli --scan --pattern 'session:*' | wc -l

Um Typen vor dem Löschen zu inspizieren:

redis-cli --scan --pattern 'session:*' | head
redis-cli TYPE session:abc123
redis-cli TTL session:abc123
redis-cli MEMORY USAGE session:abc123

TTL ist besonders nützlich für Bereinigungsentscheidungen. Wenn ein Cache-Namespace bereits vernünftige Ablaufzeiten hat, benötigen Sie möglicherweise überhaupt keine Massenlöschung. Das natürliche Ablaufen von Schlüsseln ist in der Regel weniger riskant als das Erzwingen einer großen Löschung während der Geschäftszeiten.

Löschen Sie bekannte Schlüssel mit DEL

DEL entfernt einen oder mehrere Schlüssel und gibt zurück, wie viele existierten:

DEL session:abc123
DEL session:abc123 session:def456 session:ghi789

Für kleine Schlüssel ist DEL normalerweise in Ordnung. Das Löschen eines String-Schlüssels oder eines kleinen Hashs ist nicht der beängstigende Fall. Der Fall, der wehtut, ist das Löschen eines großen aggregierten Werts, wie einer Liste mit einer riesigen Anzahl von Elementen, eines als Index verwendeten Sets oder eines Hashs, der weit über seinen ursprünglichen Zweck hinausgewachsen ist. Redis entfernt den Schlüssel aus dem Keyspace, aber das Freigeben eines großen Werts kann Zeit auf dem Hauptpfad kosten.

Wenn Sie einen Schlüssel löschen, von dem Sie wissen, dass er klein ist, verwenden Sie DEL. Wenn Sie viele Schlüssel löschen oder nicht sicher sind, wie groß sie sind, verwenden Sie UNLINK.

Bevorzugen Sie UNLINK für große oder Bulk-Löschungen

UNLINK hat die gleiche Form wie DEL:

UNLINK session:abc123
UNLINK cache:old:1 cache:old:2 cache:old:3

Der wichtige Unterschied ist die Speicherrückgewinnung. UNLINK entfernt Schlüssel sofort aus dem Keyspace und gibt dann den Speicher asynchron frei. Das macht es zu einer sichereren Standardeinstellung, wenn Sie Schlüssel bereinigen, die große Werte enthalten könnten.

Das bedeutet nicht, dass UNLINK magisch ist. Sie können immer noch Druck erzeugen, wenn Ihr Skript Millionen von Schlüsseln so schnell wie möglich entdeckt und entlinkt. Redis muss die Befehle trotzdem verarbeiten, Replikate müssen die Änderungen trotzdem empfangen und Speicher muss trotzdem zurückgewonnen werden. Drosseln Sie die Bulk-Bereinigung, damit Sie Latenz und Speicher während des Laufs beobachten können.

Eine praktische Bereinigungsschleife sieht so aus:

redis-cli --scan --pattern 'session:*' |
  xargs -r -L 100 redis-cli UNLINK

Das löscht in Batches von 100 Schlüsseln. Passen Sie die Batch-Größe an Ihre Umgebung an. In einem ruhigen Wartungsfenster können Sie größere Batches verwenden. Auf einem heißen Cache, der von benutzerorientiertem Datenverkehr gemeinsam genutzt wird, können kleinere Batches plus eine kurze Pause zwischen den Batches freundlicher sein:

redis-cli --scan --pattern 'session:*' |
while read -r key; do
  redis-cli UNLINK "$key" >/dev/null
  sleep 0.005
done

Diese Version ist langsamer, aber sie ist einfach zu stoppen und einfach zu durchschauen.

Seien Sie vorsichtig mit Musterlöschungen

Redis bietet absichtlich kein DEL user:*. Sie müssen Scannen und Löschen selbst kombinieren. Diese Reibung ist nützlich, weil Musterlöschungen der Ort sind, an dem Unfälle passieren.

Vor dem Löschen:

redis-cli --scan --pattern 'user:*' | head -50
redis-cli --scan --pattern 'user:*' | wc -l

Sehen Sie sich die erste Stichprobe an. Zählen Sie die Zielgröße. Wenn Ihre erwartete Bereinigung "ein paar tausend verlassene Sitzungen" war und die Anzahl "der größte Teil der Datenbank" ist, stoppen Sie und korrigieren Sie das Muster.

Verwenden Sie Namenskonventionen, die die Bereinigung langweilig machen:

app:prod:session:<id>
app:prod:rate-limit:<user-id>
app:prod:cache:product:<id>

Das ist ausführlicher als session:<id>, aber es ermöglicht Ihnen, einen Namespace präzise anzusprechen. In Redis Cluster können Schlüsselnamen auch Hash-Tags wie cart:{user123}:items für die Slot-Platzierung enthalten. Seien Sie sich dieser Konventionen bewusst, bevor Sie breite Muster schreiben.

FLUSHDB und FLUSHALL sind Reset-Knöpfe

FLUSHDB entfernt alle Schlüssel aus der ausgewählten Datenbank:

FLUSHDB
FLUSHDB ASYNC

FLUSHALL entfernt alle Schlüssel aus allen logischen Datenbanken:

FLUSHALL
FLUSHALL ASYNC

Modernes Redis unterstützt ASYNC- und SYNC-Modifikatoren für Flush-Befehle. ASYNC plant die Freigabe im Hintergrund, was hilft, eine große synchrone Speicherfreigabepause zu vermeiden. Es macht die Operation nicht rückgängig. Sobald die Schlüssel aus dem Keyspace verschwunden sind, sieht Ihre Anwendung sie als verschwunden an.

Bevor ich einen der beiden Befehle verwende, möchte ich drei Überprüfungen:

redis-cli ROLE
redis-cli INFO keyspace
redis-cli CONFIG GET dir

ROLE hilft zu bestätigen, ob Sie mit einem Primär- oder Replikat verbunden sind. INFO keyspace zeigt, was betroffen sein wird. CONFIG GET dir gibt oft einen weiteren Hinweis darauf, auf welcher Instanz Sie sich befinden, da Datenverzeichnisse tendenziell umgebungsspezifische Pfade enthalten.

Für Entwicklungs-Reset-Skripte seien Sie explizit:

redis-cli -h 127.0.0.1 -p 6379 -n 0 FLUSHDB ASYNC

Vermeiden Sie Skripte, die redis-cli FLUSHALL mit Standardeinstellungen ausführen. Standardeinstellungen ändern sich, wenn ein Skript auf einem anderen Host, in einem anderen Container oder von einem CI-Runner mit anderen Umgebungsvariablen ausgeführt wird.

Überprüfen Sie nach dem Löschen

Überprüfen Sie nach einer Bereinigung sowohl die Anzahl als auch das Anwendungsverhalten:

redis-cli --scan --pattern 'session:*' | wc -l
redis-cli INFO memory
redis-cli INFO stats | grep expired_keys

Der Speicher kann nach UNLINK oder asynchronem Flush nicht sofort fallen, weil die Freigabe im Hintergrund erfolgt und Allokatoren Speicher für die Wiederverwendung reserviert halten können. Das ist nicht automatisch ein Leck. Beobachten Sie used_memory, Latenz und ob sich die Schlüsselanzahl in die von Ihnen erwartete Richtung bewegt.

Für Produktionsänderungen notieren Sie den genauen Befehl und das Muster, bevor Sie ihn ausführen. Eine sichere Redis-Bereinigung ist nicht nur der richtige Befehl. Es ist der richtige Befehl, gegen die richtige Instanz, mit einem Muster, das Sie abgetastet haben, während eines Fensters, in dem Sie das Ergebnis beobachten können.

Ein sichereres Produktionsbereinigungs-Runbook

Für eine echte Bereinigung verwandle ich den Befehl gerne in ein kleines Runbook anstelle eines aus dem Gedächtnis getippten Einzeilers. Das Runbook muss nicht ausgefallen sein. Es sollte vier Fragen beantworten: welche Instanz, welches Muster, wie viele Schlüssel und wie schnell.

Beginnen Sie mit schreibgeschützten Überprüfungen:

redis-cli -h redis.example.internal -p 6379 ROLE
redis-cli -h redis.example.internal -p 6379 INFO keyspace
redis-cli -h redis.example.internal -p 6379 --scan --pattern 'app:prod:session:*' | head -20
redis-cli -h redis.example.internal -p 6379 --scan --pattern 'app:prod:session:*' | wc -l

Dann inspizieren Sie ein paar repräsentative Schlüssel:

redis-cli TYPE app:prod:session:sample
redis-cli TTL app:prod:session:sample
redis-cli MEMORY USAGE app:prod:session:sample

Wenn die Stichprobe Schlüssel zeigt, die in ein paar Minuten natürlich ablaufen sollten, warten Sie anstatt zu löschen. Wenn die Schlüssel kein TTL haben und eindeutig zu verlassenen Daten gehören, fahren Sie mit einer gedrosselten Bereinigung fort. Halten Sie ein Terminal mit Latenz oder Speicher offen:

redis-cli --latency
redis-cli INFO memory

Für gemeinsam genutzte Produktions-Redis bevorzuge ich ein Skript, das gestoppt werden kann, ohne die Absicht zu verlieren:

redis-cli --scan --pattern 'app:prod:session:*' |
while read -r key; do
  redis-cli UNLINK "$key" >/dev/null
  sleep 0.002
done

Das ist nicht die schnellste Version. Es ist die Version, die Ihnen die Chance gibt, zu bemerken, ob sich die Latenz bewegt, Kunden sich beschweren oder das Muster breiter als erwartet war. Wenn die Instanz ruhig und die Anzahl bescheiden ist, ist das Batching mit xargs -L 100 in Ordnung. Der Punkt ist, das Tempo absichtlich zu wählen.

Eine weitere Gewohnheit hilft: Speichern Sie die Anzahl vorher und nachher im Incident-Ticket oder Bereitstellungshinweis. "Gelöschte Sitzungsschlüssel" ist nicht genug. "48.213 Schlüssel gelöscht, die app:prod:session:* aus db0 auf redis-cache-01 mit UNLINK entsprechen, keine Latenzerhöhung beobachtet" ist die Art von Notiz, die später Zeit spart.