Comprendere il Keyspace di Redis: Comandi di Eliminazione e Ispezione
Scopri la potenza della gestione del keyspace di Redis con questa guida completa. Impara a ispezionare in sicurezza i tuoi dati usando `SCAN` (e perché evitare `KEYS` in produzione) e a eliminare efficientemente le chiavi con `DEL` e il non bloccante `UNLINK`. Comprendi la natura distruttiva di `FLUSHDB` e `FLUSHALL` e scopri le migliori pratiche per mantenere un'istanza Redis sana e performante.
Comprendere il Keyspace di Redis: Comandi di Eliminazione e Ispezione
Il keyspace di Redis è semplicemente l'insieme delle chiavi nel database attualmente selezionato, ma il modo in cui ispezioni ed elimini queste chiavi può determinare se una pulizia è noiosa o se la tua applicazione si blocca in mezzo al traffico.
La maggior parte dei team impara questa lezione nel modo più duro. Qualcuno deve eliminare le chiavi session:* da una cache di staging, esegue KEYS session:*, vede l'elenco e poi prova la stessa abitudine in produzione. Su un database piccolo, sembra funzionare. Su un'istanza trafficata con milioni di chiavi, il comando può tenere occupato il server abbastanza a lungo da far accodare richieste non correlate. Redis elabora i comandi molto velocemente, ma un comando che percorre l'intero keyspace deve comunque svolgere il lavoro.
Per le operazioni quotidiane, pensa in due passaggi separati: trova le chiavi in sicurezza, poi eliminale in sicurezza. Non trattare l'ispezione delle chiavi come una lettura innocua. Un comando di lettura può comunque essere costoso.
Inizia con il database che stai realmente usando
Prima di eliminare qualsiasi cosa, conferma l'endpoint e il database logico.
redis-cli -h redis.example.internal -p 6379 INFO keyspace
L'output appare così:
# Keyspace
db0:keys=154233,expires=129900,avg_ttl=2851412
db2:keys=32,expires=32,avg_ttl=60000
Questo ti dice quali database logici contengono chiavi. Molte distribuzioni Redis usano solo il database 0. Redis Cluster supporta solo il database 0, quindi FLUSHDB e FLUSHALL meritano particolare attenzione perché il solito modello mentale di "database selezionato" non è utile allo stesso modo.
Se la tua applicazione usa database numerati su Redis standalone, seleziona esplicitamente quello giusto:
redis-cli -n 2 DBSIZE
DBSIZE restituisce il numero di chiavi nel database selezionato. Non mostra i nomi e non sostituisce un passaggio di ispezione, ma è un buon controllo di integrità prima e dopo la pulizia.
Usa KEYS solo quando il keyspace è piccolo e usa e getta
KEYS pattern restituisce ogni chiave che corrisponde a un pattern in stile glob:
KEYS user:*
KEYS cache:product:???
KEYS *
Le regole del pattern sono utili: * corrisponde a qualsiasi sequenza, ? corrisponde a un carattere e gli intervalli tra parentesi come [0-9] corrispondono a un carattere dell'intervallo.
Il problema non è la correttezza. Il problema è che KEYS scansiona l'intero keyspace in un unico comando. Su un Redis di sviluppo locale con poche centinaia di chiavi, è comodo. Su una cache condivisa, può aggiungere latenza per ogni altro client mentre Redis è occupato a produrre il risultato. Il comando è documentato come un comando del keyspace con complessità lineare, quindi non dovrebbe far parte degli script di pulizia di produzione normali.
Uso ancora KEYS in due casi:
- Un Redis locale usa e getta mentre scrivo test.
- Un piccolo database di staging dove ho già controllato
DBSIZEe so che il comando non può sorprendermi.
In ogni altro caso, usa SCAN.
Usa SCAN per l'ispezione in produzione
SCAN è basato su cursore:
SCAN 0 MATCH user:* COUNT 100
Redis restituisce due cose: il cursore successivo e un lotto di chiavi. Inizia dal cursore 0. Continua a scansionare con il cursore restituito. Fermati quando Redis restituisce di nuovo il cursore 0.
1) "24576"
2) 1) "user:100"
2) "user:101"
COUNT è un suggerimento, non una promessa. Redis può restituire più chiavi, meno chiavi o anche nessuna chiave per una data iterazione. MATCH filtra ciò che viene restituito, ma Redis avanza comunque attraverso il keyspace. Un pattern ristretto è utile per ridurre il lavoro lato client, ma non rende magicamente ogni scansione gratuita.
Per il lavoro da shell, preferisci redis-cli --scan perché nasconde il ciclo del cursore:
redis-cli --scan --pattern 'session:*'
Per contare le chiavi corrispondenti senza stamparle tutte:
redis-cli --scan --pattern 'session:*' | wc -l
Per ispezionare i tipi prima di eliminare:
redis-cli --scan --pattern 'session:*' | head
redis-cli TYPE session:abc123
redis-cli TTL session:abc123
redis-cli MEMORY USAGE session:abc123
TTL è particolarmente utile per le decisioni di pulizia. Se un namespace di cache ha già scadenze ragionevoli, potresti non aver bisogno di un'eliminazione in blocco. Lasciare che le chiavi scadano naturalmente è di solito meno rischioso che forzare una grande eliminazione durante l'orario di lavoro.
Elimina le chiavi note con DEL
DEL rimuove una o più chiavi e restituisce quante esistevano:
DEL session:abc123
DEL session:abc123 session:def456 session:ghi789
Per chiavi piccole, DEL di solito va bene. Eliminare una chiave stringa o un piccolo hash non è il caso preoccupante. Il caso che fa male è eliminare un valore aggregato grande, come una lista con un enorme numero di elementi, un set usato come indice o un hash che è cresciuto ben oltre il suo scopo originale. Redis rimuove la chiave dal keyspace, ma liberare un valore grande può costare tempo sul percorso principale.
Se stai eliminando una chiave che sai essere piccola, usa DEL. Se stai eliminando molte chiavi o non sei sicuro di quanto siano grandi, usa UNLINK.
Preferisci UNLINK per eliminazioni grandi o in blocco
UNLINK ha la stessa forma di DEL:
UNLINK session:abc123
UNLINK cache:old:1 cache:old:2 cache:old:3
La differenza importante è il recupero della memoria. UNLINK rimuove le chiavi dal keyspace immediatamente, poi libera la memoria in modo asincrono. Questo lo rende un'impostazione predefinita più sicura quando stai pulendo chiavi che potrebbero contenere valori grandi.
Questo non significa che UNLINK sia magico. Puoi comunque creare pressione se il tuo script scopre e scollega milioni di chiavi il più velocemente possibile. Redis deve comunque elaborare i comandi, le repliche devono ancora ricevere le modifiche e la memoria deve ancora essere recuperata. Limita la pulizia in blocco in modo da poter monitorare la latenza e la memoria mentre viene eseguita.
Un ciclo di pulizia pratico assomiglia a questo:
redis-cli --scan --pattern 'session:*' |
xargs -r -L 100 redis-cli UNLINK
Questo elimina in lotti di 100 chiavi. Regola la dimensione del lotto per il tuo ambiente. In una finestra di manutenzione tranquilla potresti usare lotti più grandi. Su una cache calda condivisa dal traffico degli utenti, lotti più piccoli con una breve pausa tra i lotti potrebbero essere più gentili:
redis-cli --scan --pattern 'session:*' |
while read -r key; do
redis-cli UNLINK "$key" >/dev/null
sleep 0.005
done
Questa versione è più lenta, ma è facile da fermare e facile da capire.
Fai attenzione con le eliminazioni per pattern
Redis intenzionalmente non fornisce DEL user:*. Devi combinare scansione ed eliminazione da solo. Questa frizione è utile perché le eliminazioni per pattern sono dove accadono gli incidenti.
Prima di eliminare:
redis-cli --scan --pattern 'user:*' | head -50
redis-cli --scan --pattern 'user:*' | wc -l
Guarda il primo campione. Conta la dimensione target. Se la tua pulizia prevista era "qualche migliaio di sessioni abbandonate" e il conteggio è "la maggior parte del database", fermati e correggi il pattern.
Usa convenzioni di denominazione che rendano la pulizia noiosa:
app:prod:session:<id>
app:prod:rate-limit:<user-id>
app:prod:cache:product:<id>
Questo è più verboso di session:<id>, ma ti permette di indirizzare un namespace con precisione. In Redis Cluster, i nomi delle chiavi possono anche includere hash tag come cart:{user123}:items per il posizionamento degli slot. Sii consapevole di queste convenzioni prima di scrivere pattern ampi.
FLUSHDB e FLUSHALL sono pulsanti di reset
FLUSHDB rimuove tutte le chiavi dal database selezionato:
FLUSHDB
FLUSHDB ASYNC
FLUSHALL rimuove tutte le chiavi da tutti i database logici:
FLUSHALL
FLUSHALL ASYNC
Redis moderno supporta i modificatori ASYNC e SYNC per i comandi di flush. ASYNC programma la liberazione in background, il che aiuta a evitare una grande pausa sincrona di liberazione della memoria. Non rende l'operazione reversibile. Una volta che le chiavi sono sparite dal keyspace, la tua applicazione le vede come sparite.
Prima di usare uno dei due comandi, voglio tre controlli:
redis-cli ROLE
redis-cli INFO keyspace
redis-cli CONFIG GET dir
ROLE aiuta a confermare se sei connesso a un primario o a una replica. INFO keyspace mostra cosa sarà influenzato. CONFIG GET dir spesso dà un altro indizio su quale istanza sei, perché le directory dei dati tendono a includere percorsi specifici dell'ambiente.
Per gli script di reset di sviluppo, sii esplicito:
redis-cli -h 127.0.0.1 -p 6379 -n 0 FLUSHDB ASYNC
Evita script che eseguono redis-cli FLUSHALL con valori predefiniti. I valori predefiniti cambiano quando uno script viene eseguito su un altro host, in un altro contenitore o da un runner CI con diverse variabili d'ambiente.
Verifica dopo l'eliminazione
Dopo una pulizia, controlla sia il conteggio che il comportamento dell'applicazione:
redis-cli --scan --pattern 'session:*' | wc -l
redis-cli INFO memory
redis-cli INFO stats | grep expired_keys
La memoria potrebbe non scendere immediatamente dopo UNLINK o il flush asincrono perché la liberazione avviene in background e gli allocatori potrebbero mantenere la memoria riservata per il riutilizzo. Questo non è automaticamente una perdita. Osserva used_memory, la latenza e se il conteggio delle chiavi si muove nella direzione che ti aspetti.
Per le modifiche in produzione, annota il comando e il pattern esatti prima di eseguirli. Una pulizia Redis sicura non è solo il comando giusto. È il comando giusto, contro l'istanza giusta, con un pattern che hai campionato, durante una finestra in cui puoi osservare il risultato.
Un runbook di pulizia di produzione più sicuro
Per una pulizia reale, mi piace trasformare il comando in un piccolo runbook invece di una riga singola digitata a memoria. Il runbook non deve essere elaborato. Dovrebbe rispondere a quattro domande: quale istanza, quale pattern, quante chiavi e quanto velocemente.
Inizia con controlli di sola lettura:
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
Poi ispeziona alcune chiavi rappresentative:
redis-cli TYPE app:prod:session:sample
redis-cli TTL app:prod:session:sample
redis-cli MEMORY USAGE app:prod:session:sample
Se il campione mostra chiavi che dovrebbero scadere naturalmente in pochi minuti, aspetta invece di eliminare. Se le chiavi non hanno TTL e appartengono chiaramente a dati abbandonati, procedi con una pulizia limitata. Tieni un terminale aperto con la latenza o la memoria:
redis-cli --latency
redis-cli INFO memory
Per Redis di produzione condiviso, preferisco uno script che possa essere fermato senza perdere traccia dell'intento:
redis-cli --scan --pattern 'app:prod:session:*' |
while read -r key; do
redis-cli UNLINK "$key" >/dev/null
sleep 0.002
done
Questa non è la versione più veloce. È la versione che ti dà la possibilità di notare se la latenza si muove, i client si lamentano o il pattern era più ampio del previsto. Quando l'istanza è tranquilla e il conteggio è modesto, il raggruppamento con xargs -L 100 va bene. Il punto è scegliere il ritmo intenzionalmente.
Un'altra abitudine aiuta: salva il conteggio prima e dopo nel ticket dell'incidente o nella nota di distribuzione. "Chiavi di sessione eliminate" non è sufficiente. "Eliminate 48.213 chiavi corrispondenti a app:prod:session:* da db0 su redis-cache-01 usando UNLINK, nessun aumento di latenza osservato" è il tipo di nota che fa risparmiare tempo in seguito.