Dans ma base de données Redis, j'ai un certain nombre de hashs prefix:<numeric_id>
.
Parfois, je veux tous les purger de manière atomique. Comment faire cela sans utiliser un mécanisme de verrouillage distribué?
À 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 cela ressemblerait à quelque chose comme ça
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Voir le documentation EVAL .
Exécuter en bash:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
UPDATE
Ok j'ai compris. Qu'en est-il de cette façon: stockez le préfixe incrémental 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, set prefix_prefix_actuall = 3). Votre application écrira donc 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 de préfixe: 2: 1 et préfixe: 2: 2 et purger les anciennes clés.
Voici une version entièrement fonctionnelle et atomique d'une suppression générique mise en œuvre dans Lua. Il fonctionnera beaucoup plus rapidement que la version xargs en raison de la réduction beaucoup moins importante des allers-retours sur le réseau. Il est totalement atomique et bloque toute autre requête contre redis jusqu'à la fin. Si vous souhaitez supprimer les clés de manière atomique sur Redis 2.6.0 ou une version ultérieure, optez pour cette solution:
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 crédit pour l'idée lui revient à 100%.
EDIT: Par commentaire de Kikito ci-dessous, si vous avez plus de clés à supprimer que de mémoire libre sur votre serveur Redis, vous rencontrerez le erreur "trop d'éléments à décompresser" . Dans ce cas, faites-vous:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Comme suggéré par Kikito.
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 pouvant éventuellement entraîner un déni de service. Ce qui suit est une citation de sa page de documentation:
Avertissement: considère KEYS comme une commande qui ne doit être utilisée que dans des environnements de production avec une extrême prudence. Cela risque de nuire aux performances lorsqu'il est exécuté sur des bases de données volumineuses. Cette commande est destinée au débogage et à des opérations spéciales, telles que la modification de la disposition de votre espace clé. N'utilisez pas KEYS dans votre code d'application habituel. Si vous cherchez un moyen de rechercher des clés dans un sous-ensemble de votre espace de clés, envisagez d'utiliser des ensembles.
UPDATE: une ligne pour le même effet de base -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
Pour ceux qui avaient 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 pourrez continuer.
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 davantage d’aide sur la recherche de modèle de clé à partir d’ici: - https://redis.io/commands/keys . Utilisez votre modèle pratique de style glob selon vos besoins, tel que *YOUR_KEY_PREFIX*
ou YOUR_KEY_PREFIX??
ou tout autre.
Et si l’un d’entre vous a intégré la bibliothèque Redis PHP que celle 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 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*
Note: Vous devriez remplacer 'prefix' par votre préfixe de clé ...
Vous pouvez également utiliser cette commande pour supprimer les clés: -
Supposons qu'il y ait plusieurs types de clés dans votre redis, comme
Ex- 'xyz_category_fpc' ici xyz est un nom du site, et ces clés sont liées aux produits et aux catégories d'un site de commerce électronique et sont générées par FPC.
Si vous utilisez cette commande comme ci-dessous
redis-cli --scan --pattern 'key*' | xargs redis-cli del
OR
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Il supprime toutes les clés telles que 'xyz_category_fpc' (supprime les clés 1, 2 et 3). Pour supprimer les autres touches numériques 4, 5 et 6, utilisez la commande 'xyz_product_fpc' dans la commande ci-dessus.
Si vous voulez Supprimer tout dans Redis, alors suivez ces commandes-
Avec redis-cli:
Par exemple: - dans votre shell:
redis-cli flushall
redis-cli flushdb
Si vous avez un espace dans le nom des clés, vous pouvez l'utiliser en bash:
redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del
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é ne se trouve 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 à KEYS en production, mais n’est pas atomique.
Je viens d'avoir le même problème. J'ai stocké les données de session pour un utilisateur au format suivant:
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 séparée. Lorsque la session est détruite, je souhaitais supprimer toutes les données de la session en supprimant les clés avec le motif session:sessionid:*
- mais redis n’a pas cette fonction.
Ce que j'ai fait: stocker les données de session dans un hash . Je viens de créer un hachage avec l'identifiant de hachage session:sessionid
, puis j'appuie key-x
, key-y
, key-z
dans ce hachage (l'ordre ne m'importait pas) et si Je n'ai plus besoin de ce hachage Je fais juste un DEL session:sessionid
et toutes les données associées à cet identifiant de hachage ont disparu. DEL
est atomique et l'accès aux données/écriture de données dans le hachage est O (1).
FYI.
redis-cli
keys
(ceci utilise scan
)Peut-être avez-vous seulement besoin 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
Courir à l'invite
$ ./clear-redis-key.sh key_head_pattern
Je pense que ce qui pourrait vous aider est le MULTI/EXEC/DISCARD . Bien que non équivalent à 100% des transactions , vous devriez pouvoir isoler les suppressions d'autres mises à jour.
Veuillez utiliser cette commande et essayez:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
Il est simple à mettre en œuvre via la fonctionnalité "Supprimer la branche" dans FastoRedis , il suffit de sélectionner la branche que vous souhaitez supprimer.
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 utiliser pipe plutôt que 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 et interprète. La substitution de regex dans cet exemple encapsule la clé entre guillemets et échappe aux guillemets internes.
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 devez faire correspondre des dizaines, voire des centaines de millions de clés, les réponses données ici feront en sorte que Redis ne répondra pas pendant un temps assez long (minutes?), Et risque de planter en raison de la consommation de mémoire (soyez sûr, la sauvegarde en arrière-plan sera coup de poing au milieu de votre opération).
L’approche suivante est indéniablement moche, mais je n’en ai pas trouvé de meilleure. Atomicity est hors de question ici, dans ce cas, l’objectif principal est de maintenir Redis actif 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 que vous ne pouvez pas utiliser http://redis.io/commands/FLUSHDB à cause de son blocage la nature.
L'idée est simple: écrivez un script qui s'exécute en boucle et utilise O(1) opération comme http://redis.io/commands/SCAN ou http : //redis.io/commands/RANDOMKEY pour obtenir les clés, vérifie si elles correspondent 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, s'il vous plaît faites le moi savoir, je mettrai à jour la réponse.
Exemple d’implémentation avec randomkey en Ruby, en tant que tâche rake, 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
J'ai essayé la plupart des méthodes mentionnées ci-dessus mais elles ne fonctionnaient pas pour moi. Après quelques recherches, j'ai trouvé les points suivants:
-n [number]
.del
mais s'il y a des milliers ou des millions de clés, il vaut mieux utiliser unlink
car , le lien est non bloquant pendant que del bloque, pour plus d'informations, visitez cette page nlink vs delkeys
sont 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
Je soutiens toutes les réponses liées à avoir un outil ou à exécuter une expression Lua.
Une autre option de mon côté:
Nos bases de données de production et de pré-production contiennent 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’est pas possible de le faire manuellement à partir de la CLI, en particulier en ayant un sharding (512 dbs logiques dans chaque physique).
À cette fin, j'écris Java outil client qui fait tout ce travail. En cas de suppression de clés, l'utilitaire peut être très simple, avec 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();
}
}