L'une des choses qui déroutent souvent les utilisateurs qui connaissent d'autres bases de données lorsqu'ils essaient Redis, est le manque de visibilité sur la base de données :il n'y a pas d'ensemble de tables ou de collections à voyez, juste un espace clé plat et plat qui pourrait (potentiellement) avoir des millions de clés. La possibilité d'itérer à peu de frais sur cet espace clé devient donc très importante pour se familiariser avec le contenu de la base de données.
L'itération sur l'espace clé Redis a d'autres cas d'utilisation importants, parmi lesquels quelques-uns qui me viennent à l'esprit :
- la récupération de place ou le nettoyage des clés qui correspondent à un certain modèle
- Mouvement de données et modifications de schéma ou déplacement d'un certain ensemble de clés vers une autre structure de données
- débogage, échantillonnage de données, corrections de données ou recherche et correction de toutes les clés qui ont été gâchées par une modification récente
Dans cet article, nous allons approfondir les différentes options d'itération d'espace clé disponibles dans Redis.
O(N) Itérateurs :KEYS
La commande Redis KEYS renvoie toutes les clés de la base de données qui correspondent à un modèle (ou toutes les clés de l'espace clé). Des commandes similaires pour récupérer tous les champs stockés dans un hachage sont HGETALL et pour tous récupérer les membres d'un SMEMBERS. Les clés de Redis elles-mêmes sont stockées dans un dictionnaire (c'est-à-dire une table de hachage). La commande KEYS fonctionne en parcourant ce dictionnaire et en envoyant tout ce qui correspond au modèle en une seule réponse Array. Les autres commandes fonctionnent de la même manière.
La performance d'une telle opération dépend de la taille de la collection, c'est-à-dire O(N). Ainsi, l'utilisation de KEYS est fortement déconseillée dans les environnements de production avec un grand nombre de clés. Redis étant mono-thread, se bloque lors de cette itération bloquant ainsi les autres opérations. Ainsi, KEYS ne doit être utilisé que pour le débogage et d'autres occasions spéciales où les performances ne sont pas un problème (comme lorsque la base de données a été mise hors ligne pour appliquer un correctif de données). L'autre chose importante à retenir à propos de cet algorithme est qu'il envoie toutes les clés correspondantes ensemble en une seule réponse. Cela peut être extrêmement pratique lorsque l'espace clé est petit, mais créera plusieurs problèmes sur un grand espace clé. KEYS est cependant une commande préférée parmi les développeurs dans leurs propres environnements de développement.
CLÉS en action :
127.0.0.1:6379[1]> MSET un 1 deux 2 trois 3 quatre 4OK# Toutes les touches127.0.0.1:6379[1]> touches *1) "quatre"2) "trois"3) " deux"4) "une"# clés commençant par la lettre 't'127.0.0.1:6379[1]> touches t*1) "trois"2) "deux"# clés contenant un "ee"127. 0.0.1:6379[1]> touches *ee*1) "trois"
Itérateurs basés sur le curseur :SCAN
Le SCAN et ses commandes sœurs, SSCAN (pour les ensembles), HSCAN (pour les hachages) et ZSCAN (pour les ensembles triés) fournissent l'approche basée sur le curseur pour itérer sur les structures de données Redis. Ils sont disponibles dans Redis depuis la version 2.8.0.
Les clés sont renvoyées par itérations incrémentielles avec une garantie de temps constant pour chaque itération. Un curseur (un entier dans ce cas) est retourné lorsque les itérations sont initialisées et un curseur mis à jour est retourné et à chaque itération. Un cycle d'itération commence lorsque le curseur est défini sur 0 dans la requête SCAN et se termine lorsque le curseur renvoyé par le serveur est 0. En raison des nuances de l'architecture Redis et de la mise en œuvre de l'algorithme du curseur, voici quelques particularités de cette approche :
- Une itération complète récupère toujours tous les éléments qui étaient présents dans la collection du début à la fin d'une itération complète.
- Une itération complète ne renvoie jamais un élément qui n'était PAS présent dans la collection du début à la fin d'une itération complète.
- Un élément donné peut être renvoyé plusieurs fois. C'est à l'application de gérer le cas des éléments dupliqués
- Les éléments qui n'étaient pas constamment présents dans la collection lors d'une itération complète, peuvent être retournés ou non :c'est indéfini.
- Le nombre d'éléments renvoyés lors de chaque décompte varie et peut également être égal à 0. Cependant, l'itération n'est pas terminée tant que le serveur n'a pas renvoyé la valeur de curseur 0.
- Le COMPTE L'option peut être utilisée pour limiter le nombre d'éléments renvoyés à chaque itération. La valeur par défaut est 10. Cependant, elle n'est considérée que comme une suggestion et n'est pas appliquée dans tous les cas. La valeur COUNT peut être modifiée lors de chaque appel d'itération.
- Le MATCH L'option permet de spécifier des motifs comme le permet la commande KEYS.
- L'implémentation du curseur est complètement sans état côté serveur. Cela permet à des itérations (potentiellement) infinies de démarrer en parallèle. De plus, il n'est pas nécessaire de s'assurer qu'une itération continue jusqu'à la fin et peut être arrêtée à tout moment.
Malgré ses particularités, SCAN est une commande très utile et la bonne commande à choisir pour les itérations d'espace clé dans la plupart des cas d'utilisation.
SCAN est une commande très utile et la bonne commande à choisir pour les itérations d'espace clé dans #RedisClick To TweetSCAN en action
127.0.0.1:6379[1]> flushdbOK127.0.0.1:6379[1]> keys *(liste vide ou set)127.0.0.1:6379[1]> debug populate 33OK127.0.0.1:6379[ 1]> scan 0 COUNT 51) "4"2) 1) "key:1" 2) "key:9" 3) "key:13" 4) "key:29" 5) "key:23"127.0. 0.1:6379[1]> scan 4 1) "42"2) 1) "key:24" 2) "key:28" 3) "key:18" 4) "key:16" 5) "key:12 " 6) "key:2" 7) "key:6" 8) "key:31" 9) "key:27" 10) "key:19"127.0.0.1:6379[1]> scanner 421) "9 "2) 1) "touche :3" 2) "touche :4" 3) "touche :20" 4) "touche :8" 5) "touche :32" 6) "touche :5" 7) "touche :26" 8) "key:10" 9) "key:21" 10) "key:14"127.0.0.1:6379[1]> scan 9 COUNT 1001) "0"2) 1) "key:25" 2 ) "key:30" 3) "key:22" 4) "key:17" 5) "key:15" 6) "key:0" 7) "key:11" 8) "key:7"Sous le capot
L'algorithme que SCAN (et ses commandes sœurs) utilise pour parcourir est intrigant et conduit à certaines des caractéristiques de la commande que nous avons décrites ci-dessus. Antirez l'a décrit à un niveau élevé dans son article de blog et il est expliqué (un peu mieux) dans les commentaires ci-dessus l'implémentation (fonction dictScan). Le décrire en détail rendra ce message trop long, je donnerai donc suffisamment de description pour que ses implications soient évidentes.
- La plupart des structures de données Redis sont représentées en interne sous forme de dictionnaires (au moins partiellement dans le cas d'ensembles triés). Ils sont implémentés sous forme de tables de hachage de taille puissance de deux avec chaînage pour les collisions. Le défi d'écrire un algorithme itératif basé sur un curseur ici est de pouvoir gérer la croissance et la réduction du hachage sans sacrifier les principes Redis de simplicité (de l'API) et de vitesse.
- SCAN analyse essentiellement un tas de seaux de hachage à chaque itération et renvoie les éléments correspondant au modèle dans ceux-ci. Puisqu'il ne regarde qu'une liste fixe de compartiments, certaines itérations peuvent parfois ne renvoyer aucune valeur.
- Le curseur renvoyé est essentiellement un décalage dans la table de hachage en cours d'itération. Il traite de la croissance et de la réduction des tables de hachage (c'est-à-dire du rehachage) par une manipulation intelligente des bits de niveau supérieur du décalage tout en augmentant le décalage ainsi que les propriétés de la table de hachage. Les implications de cette approche sont que les nouveaux éléments ajoutés au cours de l'itération peuvent ou non être renvoyés. Cependant, le curseur lui-même n'aurait pas besoin de redémarrer lors d'un changement de taille de la table de hachage.
- Un bucket donné ne doit être visité qu'une seule fois et toutes ses clés doivent être retournées en une seule fois. C'est encore une fois pour s'assurer que le redimensionnement du hachage (c'est-à-dire le rehachage) ne complique pas la progression de l'itération. Cependant, cela conduit à ce que l'argument COUNT ne soit pas strictement applicable.
- Étant donné que l'approche ci-dessus est complètement sans état côté serveur, cela implique essentiellement que les itérations peuvent être arrêtées ou qu'un grand nombre d'itérations peuvent être démarrées en parallèle sans augmenter l'utilisation de la mémoire.
Résumé
À un niveau élevé, deux choix sont disponibles pour itérer sur l'espace clé Redis :
- Utilisez KEYS lorsque les performances ne sont pas un problème ou lorsque l'espace clé est de taille raisonnable.
- À tout autre moment, utilisez SCAN.
Saviez-vous que nous prenons désormais en charge l'hébergement pour Redis™* ? Bénéficiez d'un hébergement entièrement géré pour Redis™ dans la sécurité de votre propre compte cloud et tirez parti des crédits AWS/Azure pour vos déploiements Redis™.