Comprendre le keyspace Redis : commandes de suppression et d'inspection

Découvrez la gestion du keyspace Redis avec ce guide complet. Apprenez à inspecter vos données en toute sécurité avec `SCAN` (et pourquoi éviter `KEYS` en production) et à supprimer efficacement des clés avec `DEL` et le non-bloquant `UNLINK`. Comprenez la nature destructive de `FLUSHDB` et `FLUSHALL` et découvrez les bonnes pratiques pour maintenir une instance Redis saine et performante.

Comprendre le keyspace Redis : commandes de suppression et d'inspection

Le keyspace Redis est simplement l'ensemble des clés dans la base de données actuellement sélectionnée, mais la façon dont vous inspectez et supprimez ces clés peut décider si un nettoyage est ennuyeux ou si votre application se bloque au milieu du trafic.

La plupart des équipes l'apprennent à leurs dépens. Quelqu'un doit supprimer les clés session:* d'un cache de staging, exécute KEYS session:*, voit la liste, puis essaie la même habitude en production. Sur une petite base de données, cela semble acceptable. Sur une instance chargée avec des millions de clés, la commande peut bloquer le serveur assez longtemps pour que des requêtes non liées s'accumulent derrière elle. Redis traite les commandes très rapidement, mais une commande qui parcourt tout le keyspace doit quand même effectuer le travail.

Pour les opérations quotidiennes, pensez en deux étapes distinctes : trouver les clés en toute sécurité, puis les supprimer en toute sécurité. Ne traitez pas l'inspection des clés comme une lecture inoffensive. Une commande de lecture peut encore être coûteuse.

Commencez par la base de données que vous utilisez réellement

Avant de supprimer quoi que ce soit, confirmez le point de terminaison et la base de données logique.

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

La sortie ressemble à ceci :

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

Cela vous indique quelles bases de données logiques contiennent des clés. De nombreux déploiements Redis n'utilisent que la base de données 0. Redis Cluster ne prend en charge que la base de données 0, donc FLUSHDB et FLUSHALL méritent une attention particulière car le modèle mental habituel de "base de données sélectionnée" n'est pas utile de la même manière.

Si votre application utilise des bases de données numérotées sur Redis autonome, sélectionnez la bonne explicitement :

redis-cli -n 2 DBSIZE

DBSIZE renvoie le nombre de clés dans la base de données sélectionnée. Il n'affiche pas les noms et ne remplace pas une passe d'inspection, mais c'est une bonne vérification de cohérence avant et après le nettoyage.

Utilisez KEYS uniquement lorsque le keyspace est petit et jetable

KEYS pattern renvoie chaque clé correspondant à un motif de style glob :

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

Les règles de motif sont pratiques : * correspond à n'importe quelle séquence, ? correspond à un caractère, et les plages entre crochets comme [0-9] correspondent à un caractère de la plage.

Le problème n'est pas l'exactitude. Le problème est que KEYS analyse l'ensemble du keyspace en une seule commande. Sur un Redis de développement local avec quelques centaines de clés, c'est pratique. Sur un cache partagé, cela peut ajouter de la latence pour tous les autres clients pendant que Redis produit le résultat. La commande est documentée comme une commande keyspace avec une complexité linéaire, elle ne devrait donc pas faire partie des scripts de nettoyage de production normaux.

J'utilise encore KEYS dans deux cas :

  • Un Redis local jetable lors de l'écriture de tests.
  • Une petite base de données de staging où j'ai déjà vérifié DBSIZE et je sais que la commande ne peut pas me surprendre.

Partout ailleurs, utilisez SCAN.

Utilisez SCAN pour l'inspection en production

SCAN est basé sur un curseur :

SCAN 0 MATCH user:* COUNT 100

Redis renvoie deux choses : le prochain curseur et un lot de clés. Commencez au curseur 0. Continuez à analyser avec le curseur renvoyé. Arrêtez-vous lorsque Redis renvoie à nouveau le curseur 0.

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

COUNT est une indication, pas une promesse. Redis peut renvoyer plus de clés, moins de clés, ou même aucune clé pour une itération donnée. MATCH filtre ce qui est renvoyé, mais Redis avance toujours dans le keyspace. Un motif étroit est utile pour réduire le travail côté client, mais il ne rend pas magiquement chaque analyse gratuite.

Pour le travail en shell, préférez redis-cli --scan car il masque la boucle de curseur :

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

Pour compter les clés correspondantes sans toutes les imprimer :

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

Pour inspecter les types avant de supprimer :

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

TTL est particulièrement utile pour les décisions de nettoyage. Si un espace de noms de cache a déjà des expirations raisonnables, vous n'avez peut-être pas besoin d'une suppression en masse du tout. Laisser les clés expirer naturellement est généralement moins risqué que de forcer une grosse suppression pendant les heures de travail.

Supprimez les clés connues avec DEL

DEL supprime une ou plusieurs clés et renvoie le nombre de clés existantes :

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

Pour les petites clés, DEL est généralement acceptable. La suppression d'une clé de chaîne ou d'un petit hachage n'est pas le cas effrayant. Le cas qui fait mal est la suppression d'une grande valeur agrégée, comme une liste avec un nombre énorme d'éléments, un ensemble utilisé comme index, ou un hachage qui a grandi bien au-delà de son objectif initial. Redis supprime la clé du keyspace, mais libérer une grande valeur peut coûter du temps sur le chemin principal.

Si vous supprimez une clé dont vous savez qu'elle est petite, utilisez DEL. Si vous supprimez plusieurs clés ou si vous n'êtes pas sûr de leur taille, utilisez UNLINK.

Préférez UNLINK pour les suppressions volumineuses ou en masse

UNLINK a la même forme que DEL :

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

La différence importante est la récupération de mémoire. UNLINK supprime les clés du keyspace immédiatement, puis libère la mémoire de manière asynchrone. Cela en fait une valeur par défaut plus sûre lorsque vous nettoyez des clés qui peuvent contenir de grandes valeurs.

Cela ne signifie pas que UNLINK est magique. Vous pouvez toujours créer une pression si votre script découvre et délie des millions de clés aussi vite que possible. Redis doit toujours traiter les commandes, les réplicas doivent toujours recevoir les modifications, et la mémoire doit toujours être récupérée. Limitez le nettoyage en masse afin de pouvoir surveiller la latence et la mémoire pendant son exécution.

Une boucle de nettoyage pratique ressemble à ceci :

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

Cela supprime par lots de 100 clés. Ajustez la taille du lot à votre environnement. Pendant une fenêtre de maintenance calme, vous pouvez utiliser des lots plus grands. Sur un cache chaud partagé par le trafic utilisateur, des lots plus petits avec une courte pause entre les lots peuvent être plus doux :

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

Cette version est plus lente, mais elle est facile à arrêter et facile à comprendre.

Soyez prudent avec les suppressions par motif

Redis ne fournit intentionnellement pas DEL user:*. Vous devez combiner vous-même l'analyse et la suppression. Cette friction est utile car les suppressions par motif sont là où les accidents se produisent.

Avant de supprimer :

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

Regardez le premier échantillon. Comptez la taille cible. Si votre nettoyage attendu était "quelques milliers de sessions abandonnées" et que le nombre est "la plupart de la base de données", arrêtez-vous et corrigez le motif.

Utilisez des conventions de nommage qui rendent le nettoyage ennuyeux :

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

C'est plus verbeux que session:<id>, mais cela vous permet de cibler un espace de noms avec précision. Dans Redis Cluster, les noms de clés peuvent également inclure des hash tags comme cart:{user123}:items pour le placement des emplacements. Soyez conscient de ces conventions avant d'écrire des motifs larges.

FLUSHDB et FLUSHALL sont des boutons de réinitialisation

FLUSHDB supprime toutes les clés de la base de données sélectionnée :

FLUSHDB
FLUSHDB ASYNC

FLUSHALL supprime toutes les clés de toutes les bases de données logiques :

FLUSHALL
FLUSHALL ASYNC

Redis moderne prend en charge les modificateurs ASYNC et SYNC pour les commandes de vidage. ASYNC planifie la libération en arrière-plan, ce qui aide à éviter une longue pause de libération de mémoire synchrone. Cela ne rend pas l'opération réversible. Une fois que les clés sont supprimées du keyspace, votre application les voit comme supprimées.

Avant d'utiliser l'une ou l'autre commande, je veux trois vérifications :

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

ROLE aide à confirmer si vous êtes connecté à un primaire ou à un réplica. INFO keyspace montre ce qui sera affecté. CONFIG GET dir donne souvent un autre indice sur l'instance sur laquelle vous vous trouvez, car les répertoires de données ont tendance à inclure des chemins spécifiques à l'environnement.

Pour les scripts de réinitialisation de développement, soyez explicite :

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

Évitez les scripts qui exécutent redis-cli FLUSHALL avec les valeurs par défaut. Les valeurs par défaut changent lorsqu'un script s'exécute sur un autre hôte, dans un autre conteneur, ou à partir d'un exécuteur CI avec des variables d'environnement différentes.

Vérifiez après la suppression

Après un nettoyage, vérifiez à la fois le nombre et le comportement de l'application :

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

La mémoire peut ne pas chuter instantanément après UNLINK ou un vidage asynchrone car la libération se fait en arrière-plan et les allocateurs peuvent conserver la mémoire réservée pour une réutilisation. Ce n'est pas automatiquement une fuite. Surveillez used_memory, la latence et si le nombre de clés évolue dans la direction attendue.

Pour les changements en production, notez la commande exacte et le motif avant de l'exécuter. Un nettoyage Redis sûr n'est pas seulement la bonne commande. C'est la bonne commande, sur la bonne instance, avec un motif que vous avez échantillonné, pendant une fenêtre où vous pouvez surveiller le résultat.

Un runbook de nettoyage de production plus sûr

Pour un vrai nettoyage, j'aime transformer la commande en un petit runbook plutôt qu'en une ligne tapée de mémoire. Le runbook n'a pas besoin d'être sophistiqué. Il doit répondre à quatre questions : quelle instance, quel motif, combien de clés, et à quelle vitesse.

Commencez par des vérifications en lecture seule :

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

Ensuite, inspectez quelques clés représentatives :

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

Si l'échantillon montre des clés qui devraient naturellement expirer dans quelques minutes, attendez plutôt que de supprimer. Si les clés n'ont pas de TTL et appartiennent clairement à des données abandonnées, procédez à un nettoyage limité. Gardez un terminal ouvert avec la latence ou la mémoire :

redis-cli --latency
redis-cli INFO memory

Pour un Redis de production partagé, je préfère un script qui peut être arrêté sans perdre la trace de l'intention :

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

Ce n'est pas la version la plus rapide. C'est la version qui vous donne une chance de remarquer si la latence bouge, les clients se plaignent, ou le motif était plus large que prévu. Lorsque l'instance est calme et que le nombre est modeste, le traitement par lots avec xargs -L 100 est acceptable. Le but est de choisir le rythme intentionnellement.

Une autre habitude aide : enregistrez le nombre avant et après dans le ticket d'incident ou la note de déploiement. "Clés de session supprimées" ne suffit pas. "48 213 clés correspondant à app:prod:session:* supprimées de db0 sur redis-cache-01 en utilisant UNLINK, aucune augmentation de latence observée" est le genre de note qui fait gagner du temps plus tard.