Dans ma base de données Redis, j'ai un certain nombre de prefix:<numeric_id>
hachages.
Parfois, je veux tous les purger atomiquement. Comment faire cela sans utiliser un mécanisme de verrouillage distribué?
Dans ma base de données Redis, j'ai un certain nombre de prefix:<numeric_id>
hachages.
Parfois, je veux tous les purger atomiquement. Comment faire cela sans utiliser un mécanisme de verrouillage distribué?
Réponses:
À partir de redis 2.6.0, vous pouvez exécuter des scripts lua, qui s'exécutent de manière atomique. Je n'en ai jamais écrit, mais je pense que ça ressemblerait à quelque chose comme ça
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Avertissement : Comme le dit le document Redis , en raison de performances importantes, la
keys
commande ne doit pas être utilisée pour les opérations normales de production, cette commande est destinée au débogage et aux opérations spéciales. Lire la suite
Voir la documentation EVAL .
EVAL "local keys = redis.call('keys', ARGV[1]) \n for i=1,#keys,5000 do \n redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) \n end \n return keys" 0 prefix:*
del prefix:*
être une opération fondamentale: /
EVAL "return redis.call('del', 'defaultKey', unpack(redis.call('keys', ARGV[1])))" 0 prefix:*
Exécutez en bash:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
MISE À JOUR
Ok j'ai compris. Qu'en est-il de cette façon: stockez le préfixe incrémentiel supplémentaire actuel et ajoutez-le à toutes vos clés. Par exemple:
Vous avez des valeurs comme celle-ci:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
Lorsque vous devez purger des données, vous modifiez d'abord prefix_actuall (par exemple, définissez prefix_prefix_actuall = 3), de sorte que votre application écrira de nouvelles données dans les clés prefix: 3: 1 et prefix: 3: 2. Ensuite, vous pouvez prendre en toute sécurité les anciennes valeurs du préfixe: 2: 1 et du préfixe: 2: 2 et purger les anciennes clés.
redis-cli KEYS "prefix:*" | xargs --delim='\n' redis-cli DEL
redis-cli -n 3 KEYS "prefix:*" | xargs redis-cli -n 3 DEL
Voici une version entièrement fonctionnelle et atomique d'une suppression générique implémentée dans Lua. Il fonctionnera beaucoup plus rapidement que la version xargs en raison de beaucoup moins de va-et-vient réseau, et il est complètement atomique, bloquant toutes les autres demandes contre redis jusqu'à ce qu'il se termine. Si vous souhaitez supprimer atomiquement des clés sur Redis 2.6.0 ou supérieur, c'est certainement la voie à suivre:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
Ceci est une version de travail de l'idée de @ mcdizzle dans sa réponse à cette question. Le mérite de l'idée à 100% lui revient.
EDIT: Selon le commentaire de Kikito ci-dessous, si vous avez plus de clés à supprimer que de mémoire libre sur votre serveur Redis, vous rencontrerez l' erreur "trop d'éléments à décompresser" . Dans ce cas, faites:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Comme l'a suggéré Kikito.
for _,k in ipairs(redis.call('keys', KEYS[1])) do redis.call('del', k) end
unpack
transforme une table en une "liste de variables indépendantes" (d'autres langues appellent cela explode
) mais le nombre maximum ne dépend pas de la mémoire système; il est fixé en lua à travers la LUAI_MAXSTACK
constante. Dans Lua 5.1 et LuaJIT, c'est 8000 et dans Lua 5.2, c'est 100000. L'option de boucle for est recommandée IMO.
EVAL
car elle ne spécifie pas à l'avance les clés sur lesquelles elle fonctionnera. Il devrait fonctionner sur une seule instance, mais ne vous attendez pas à ce qu'il fonctionne avec Redis Cluster.
Avertissement: la solution suivante ne fournit pas d'atomicité.
À partir de la v2.8, vous voulez vraiment utiliser la commande SCAN au lieu de KEYS [1]. Le script Bash suivant illustre la suppression de clés par modèle:
#!/bin/bash
if [ $# -ne 3 ]
then
echo "Delete keys from Redis matching a pattern using SCAN & DEL"
echo "Usage: $0 <host> <port> <pattern>"
exit 1
fi
cursor=-1
keys=""
while [ $cursor -ne 0 ]; do
if [ $cursor -eq -1 ]
then
cursor=0
fi
reply=`redis-cli -h $1 -p $2 SCAN $cursor MATCH $3`
cursor=`expr "$reply" : '\([0-9]*[0-9 ]\)'`
keys=${reply##[0-9]*[0-9 ]}
redis-cli -h $1 -p $2 DEL $keys
done
[1] KEYS est une commande dangereuse qui peut potentiellement entraîner un DoS. Ce qui suit est une citation de sa page de documentation:
Avertissement: considérez KEYS comme une commande qui ne doit être utilisée que dans des environnements de production avec une extrême prudence. Il peut ruiner les performances lorsqu'il est exécuté sur de grandes bases de données. Cette commande est destinée au débogage et aux opérations spéciales, telles que la modification de la disposition de votre espace de clés. N'utilisez pas KEYS dans votre code d'application habituel. Si vous cherchez un moyen de trouver des clés dans un sous-ensemble de votre espace de clés, pensez à utiliser des ensembles.
MISE À JOUR: une doublure pour le même effet de base -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
-n 1
à chaque redis-cli
invocation:redis-cli -n 1 --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli -n 1 DEL
Pour ceux qui ont du mal à analyser d'autres réponses:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
Remplacez key:*:pattern
par votre propre modèle et entrez-le dans redis-cli
et vous êtes prêt à partir.
Crédit lisco de: http://redis.io/commands/del
J'utilise la commande ci-dessous dans redis 3.2.8
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
Vous pouvez obtenir plus d'aide concernant la recherche de modèles de clés à partir d'ici: - https://redis.io/commands/keys . Utilisez votre modèle de style glob pratique selon vos besoins comme *YOUR_KEY_PREFIX*
ou YOUR_KEY_PREFIX??
ou tout autre.
Et si l'un d'entre vous a intégré la bibliothèque PHP Redis, la fonction ci-dessous vous aidera.
flushRedisMultipleHashKeyUsingPattern("*YOUR_KEY_PATTERN*"); //function call
function flushRedisMultipleHashKeyUsingPattern($pattern='')
{
if($pattern==''){
return true;
}
$redisObj = $this->redis;
$getHashes = $redisObj->keys($pattern);
if(!empty($getHashes)){
$response = call_user_func_array(array(&$redisObj, 'del'), $getHashes); //setting all keys as parameter of "del" function. Using this we can achieve $redisObj->del("key1","key2);
}
}
Merci :)
La solution de @ mcdizle ne fonctionne pas, elle ne fonctionne que pour une seule entrée.
Celui-ci fonctionne pour toutes les clés avec le même préfixe
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
Remarque: vous devez remplacer «préfixe» par votre préfixe de clé ...
Vous pouvez également utiliser cette commande pour supprimer les clés: -
Supposons qu'il existe de nombreux types de clés dans votre redis comme-
Ex- ' xyz_category_fpc ' ici xyz est un nom de site , et ces clés sont liées aux produits et catégories d'un site de commerce électronique et générées par FPC.
Si vous utilisez cette commande comme ci-dessous-
redis-cli --scan --pattern 'key*' | xargs redis-cli del
OU
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Il supprime toutes les clés comme « xyz_category_fpc » (supprimer 1, 2 et 3 clés). Pour supprimer les autres touches numériques 4, 5 et 6, utilisez ' xyz_product_fpc ' dans la commande ci-dessus.
Si vous souhaitez tout supprimer dans Redis , suivez ces commandes -
Avec redis-cli:
Par exemple: - dans votre shell:
redis-cli flushall
redis-cli flushdb
redis-cli del
n'est pas atomique.
La réponse de @ itamar est excellente, mais l'analyse de la réponse ne fonctionnait pas pour moi, en particulier. dans le cas où aucune clé n'est trouvée dans un scan donné. Une solution éventuellement plus simple, directement depuis la console:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
Cela utilise également SCAN, qui est préférable aux clés en production, mais n'est pas atomique.
J'ai juste eu le même problème. J'ai stocké les données de session pour un utilisateur au format:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
Ainsi, chaque entrée était une paire clé-valeur distincte. Lorsque la session est détruite, je voulais supprimer toutes les données de session en supprimant les clés avec le modèle session:sessionid:*
- mais redis n'a pas une telle fonction.
Ce que j'ai fait: stocker les données de session dans un hachage . Je viens de créer un hachage avec l'identifiant de hachage session:sessionid
puis je pousse key-x
, key-y
, key-z
dans ce hachage (ordre n'a pas d' importance pour moi) et si je ne avez pas besoin que hachage plus je fais juste DEL session:sessionid
et toutes les données associées à cet identifiant de hachage est disparu. DEL
est atomique et accéder aux données / écrire des données dans le hachage est O (1).
Je pense que ce qui pourrait vous aider est le MULTI / EXEC / DISCARD . Bien qu'il ne soit pas équivalent à 100% des transactions , vous devriez pouvoir isoler les suppressions des autres mises à jour.
Pour info.
redis-cli
keys
(cela utilise scan
)Peut-être n'avez-vous besoin que de modifier les majuscules.
scan-match.sh
#!/bin/bash
rcli=“/YOUR_PATH/redis-cli"
default_server="YOUR_SERVER"
default_port="YOUR_PORT"
servers=`$rcli -h $default_server -p $default_port cluster nodes | grep master | awk '{print $2}' | sed 's/:.*//'`
if [ x"$1" == "x" ]; then
startswith="DEFAULT_PATTERN"
else
startswith="$1"
fi
MAX_BUFFER_SIZE=1000
for server in $servers; do
cursor=0
while
r=`$rcli -h $server -p $default_port scan $cursor match "$startswith*" count $MAX_BUFFER_SIZE `
cursor=`echo $r | cut -f 1 -d' '`
nf=`echo $r | awk '{print NF}'`
if [ $nf -gt 1 ]; then
for x in `echo $r | cut -f 1 -d' ' --complement`; do
echo $x
done
fi
(( cursor != 0 ))
do
:
done
done
clear-redis-key.sh
#!/bin/bash
STARTSWITH="$1"
RCLI=YOUR_PATH/redis-cli
HOST=YOUR_HOST
PORT=6379
RCMD="$RCLI -h $HOST -p $PORT -c "
./scan-match.sh $STARTSWITH | while read -r KEY ; do
$RCMD del $KEY
done
Exécuter à l'invite bash
$ ./clear-redis-key.sh key_head_pattern
D'autres réponses peuvent ne pas fonctionner si votre clé contient des caractères spéciaux - Guide$CLASSMETADATA][1]
par exemple. Enveloppant chaque clé dans des guillemets, elles seront correctement supprimées:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
Une version utilisant SCAN plutôt que KEYS (comme recommandé pour les serveurs de production) et --pipe
plutôt que xargs.
Je préfère le pipe aux xargs car il est plus efficace et fonctionne lorsque vos clés contiennent des guillemets ou d'autres caractères spéciaux que votre shell essaie d'interpréter. La substitution d'expression régulière dans cet exemple encapsule la clé entre guillemets doubles et échappe à tout guillemet double à l'intérieur.
export REDIS_HOST=your.hostname.com
redis-cli -h "$REDIS_HOST" --scan --pattern "YourPattern*" > /tmp/keys
time cat /tmp/keys | perl -pe 's/"/\\"/g;s/^/DEL "/;s/$/"/;' | redis-cli -h "$REDIS_HOST" --pipe
Ce n'est pas une réponse directe à la question, mais puisque je suis arrivé ici en cherchant mes propres réponses, je vais le partager ici.
Si vous avez des dizaines ou des centaines de millions de clés que vous devez faire correspondre, les réponses données ici rendront Redis non réactif pendant une durée significative (minutes?), Et risquent de planter en raison de la consommation de mémoire (assurez-vous, la sauvegarde en arrière-plan sera coup de pied au milieu de votre opération).
L'approche suivante est indéniablement laide, mais je n'en ai pas trouvé de meilleure. L'atomicité est hors de question ici, dans ce cas, l'objectif principal est de garder Redis en place et réactif 100% du temps. Cela fonctionnera parfaitement si vous avez toutes vos clés dans l'une des bases de données et que vous n'avez pas besoin de faire correspondre un modèle, mais ne pouvez pas utiliser http://redis.io/commands/FLUSHDB en raison de sa nature bloquante.
L'idée est simple: écrire un script qui s'exécute en boucle et utilise l'opération O (1) comme http://redis.io/commands/SCAN ou http://redis.io/commands/RANDOMKEY pour obtenir les clés, vérifie si elles correspondre au modèle (si vous en avez besoin) et http://redis.io/commands/DEL les un par un.
S'il y a une meilleure façon de le faire, faites-le moi savoir, je mettrai à jour la réponse.
Exemple d'implémentation avec randomkey dans Ruby, comme tâche de râteau, un substitut non bloquant de quelque chose comme redis-cli -n 3 flushdb
:
desc 'Cleanup redis'
task cleanup_redis: :environment do
redis = Redis.new(...) # connection to target database number which needs to be wiped out
counter = 0
while key = redis.randomkey
puts "Deleting #{counter}: #{key}"
redis.del(key)
counter += 1
end
end
Il est simple à mettre en œuvre via la fonctionnalité "Supprimer la branche" dans FastoRedis , sélectionnez simplement la branche que vous souhaitez supprimer.
Veuillez utiliser cette commande et essayez:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
J'ai essayé la plupart des méthodes mentionnées ci-dessus mais elles n'ont pas fonctionné pour moi, après quelques recherches, j'ai trouvé ces points:
-n [number]
del
mais s'il y a des milliers ou des millions de clés , il est préférable d'utiliser unlink
parce que unlink est non bloquant tout del bloque, pour plus d' informations , visitez cette page unlink vs delkeys
sont également comme del et bloquej'ai donc utilisé ce code pour supprimer des clés par modèle:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
suppression de la masse atomique du pauvre?
peut-être pourriez-vous les régler tous sur EXPIREAT la même seconde - comme quelques minutes dans le futur - puis attendre ce moment et les voir tous "s'autodétruire" en même temps.
mais je ne sais pas vraiment à quel point ce serait atomique.
À partir de maintenant, vous pouvez utiliser un client redis et effectuer un premier SCAN (prend en charge la correspondance de modèles) puis SUPPRIMER chaque clé individuellement.
Cependant, il y a un problème sur redis github officiel pour créer un patter-matching-del ici , allez lui montrer un peu d'amour si vous le trouvez utile!
Je soutiens toutes les réponses liées à l'utilisation d'un outil ou à l'exécution de l'expression Lua.
Une option de plus de mon côté:
Dans nos bases de données de production et de pré-production, il y a des milliers de clés. De temps en temps, nous devons supprimer certaines clés (par un masque), les modifier selon certains critères, etc. Bien sûr, il n'y a aucun moyen de le faire manuellement à partir de la CLI, en particulier avec le partage (512 dbs logiques dans chaque physique).
Dans ce but, j'écris un outil client java qui fait tout ce travail. En cas de suppression de clés, l'utilitaire peut être très simple, il n'y a qu'une seule classe:
public class DataCleaner {
public static void main(String args[]) {
String keyPattern = args[0];
String host = args[1];
int port = Integer.valueOf(args[2]);
int dbIndex = Integer.valueOf(args[3]);
Jedis jedis = new Jedis(host, port);
int deletedKeysNumber = 0;
if(dbIndex >= 0){
deletedKeysNumber += deleteDataFromDB(jedis, keyPattern, dbIndex);
} else {
int dbSize = Integer.valueOf(jedis.configGet("databases").get(1));
for(int i = 0; i < dbSize; i++){
deletedKeysNumber += deleteDataFromDB(jedis, keyPattern, i);
}
}
if(deletedKeysNumber == 0) {
System.out.println("There is no keys with key pattern: " + keyPattern + " was found in database with host: " + host);
}
}
private static int deleteDataFromDB(Jedis jedis, String keyPattern, int dbIndex) {
jedis.select(dbIndex);
Set<String> keys = jedis.keys(keyPattern);
for(String key : keys){
jedis.del(key);
System.out.println("The key: " + key + " has been deleted from database index: " + dbIndex);
}
return keys.size();
}
}
La commande ci-dessous a fonctionné pour moi.
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
Spring RedisTemplate lui-même fournit la fonctionnalité. RedissonClient dans la dernière version a déprécié la fonctionnalité "deleteByPattern".
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
keys
et delete
.