En mi Redis DB tengo varios prefix:<numeric_id>
hashes.
A veces quiero purgarlos a todos atómicamente. ¿Cómo hago esto sin usar algún mecanismo de bloqueo distribuido?
En mi Redis DB tengo varios prefix:<numeric_id>
hashes.
A veces quiero purgarlos a todos atómicamente. ¿Cómo hago esto sin usar algún mecanismo de bloqueo distribuido?
Respuestas:
A partir de redis 2.6.0, puede ejecutar scripts lua, que se ejecutan atómicamente. Nunca he escrito uno, pero creo que se vería así
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Advertencia : como dice el documento de Redis , debido a los problemas de rendimiento, el
keys
comando no debe usarse para operaciones regulares en producción, este comando está destinado a la depuración y operaciones especiales. Lee mas
Consulte la documentación de 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:*
ser una operación fundamental: /
EVAL "return redis.call('del', 'defaultKey', unpack(redis.call('keys', ARGV[1])))" 0 prefix:*
Ejecutar en bash:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
ACTUALIZAR
Esta bien, entendí. Qué hay de esta manera: almacene el prefijo incremental adicional actual y agréguelo a todas sus claves. Por ejemplo:
Tienes valores como este:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
Cuando necesite purgar datos, primero cambie prefix_actuall (por ejemplo, configure prefix_prefix_actuall = 3), por lo que su aplicación escribirá nuevos datos en las claves prefijo: 3: 1 y prefijo: 3: 2. Entonces puede tomar con seguridad los valores antiguos del prefijo: 2: 1 y el prefijo: 2: 2 y purgar las claves antiguas.
redis-cli KEYS "prefix:*" | xargs --delim='\n' redis-cli DEL
redis-cli -n 3 KEYS "prefix:*" | xargs redis-cli -n 3 DEL
Aquí hay una versión completamente funcional y atómica de una eliminación de comodines implementada en Lua. Se ejecutará mucho más rápido que la versión xargs debido a que la red es mucho menor, y es completamente atómica, bloqueando cualquier otra solicitud contra redis hasta que finalice. Si desea eliminar claves atómicamente en Redis 2.6.0 o superior, este es definitivamente el camino a seguir:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
Esta es una versión funcional de la idea de @ mcdizzle en su respuesta a esta pregunta. El crédito por la idea le corresponde al 100%.
EDITAR: Según el comentario de Kikito a continuación, si tiene más claves para eliminar que memoria libre en su servidor Redis, se encontrará con el error "demasiados elementos para descomprimir" . En ese caso, haz:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Como sugirió Kikito.
for _,k in ipairs(redis.call('keys', KEYS[1])) do redis.call('del', k) end
unpack
transforma una tabla en una "lista de variables independientes" (otros idiomas lo llaman explode
) pero el número máximo no depende de la memoria del sistema; se arregla en lua a través de la LUAI_MAXSTACK
constante. En Lua 5.1 y LuaJIT es 8000 y en Lua 5.2 es 100000. Se recomienda la opción for loop IMO.
EVAL
ya que no especifica de antemano las teclas con las que operará. Debería funcionar en una sola instancia, pero no espere que funcione con Redis Cluster.
Descargo de responsabilidad: la siguiente solución no proporciona atomicidad.
A partir de v2.8, realmente desea utilizar el comando SCAN en lugar de KEYS [1]. La siguiente secuencia de comandos Bash muestra la eliminación de claves por patrón:
#!/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 es un comando peligroso que potencialmente puede resultar en un DoS. La siguiente es una cita de su página de documentación:
Advertencia: considere KEYS como un comando que solo debe usarse en entornos de producción con extremo cuidado. Puede arruinar el rendimiento cuando se ejecuta en grandes bases de datos. Este comando está destinado a la depuración y operaciones especiales, como cambiar el diseño del espacio de teclas. No use KEYS en su código de aplicación habitual. Si está buscando una manera de encontrar claves en un subconjunto de su espacio de claves, considere usar conjuntos.
ACTUALIZACIÓN: un trazador de líneas para el mismo efecto básico -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
-n 1
a cada redis-cli
invocación:redis-cli -n 1 --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli -n 1 DEL
Para aquellos que tenían problemas para analizar otras respuestas:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
Reemplace key:*:pattern
con su propio patrón e ingrese esto redis-cli
y estará listo para comenzar .
Crédito lisco de: http://redis.io/commands/del
Estoy usando el siguiente comando en redis 3.2.8
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
Puede obtener más ayuda relacionada con la búsqueda de patrones de teclas desde aquí: - https://redis.io/commands/keys . Utilice su cómoda de estilo patrón glob como por su exigencia como *YOUR_KEY_PREFIX*
o YOUR_KEY_PREFIX??
, o cualquier otro.
Y si alguno de ustedes ha integrado la biblioteca PHP de Redis, la siguiente función lo ayudará.
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);
}
}
Gracias :)
La solución de @ mcdizle no funciona, solo funciona para una entrada.
Este funciona para todas las teclas con el mismo prefijo
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
Nota: Debe reemplazar 'prefijo' con su prefijo clave ...
También puede usar este comando para eliminar las teclas: -
Supongamos que hay muchos tipos de teclas en su redis como:
Ex ' xyz_category_fpc ' aquí XYZ es un nombre del sitio , y estas claves están relacionadas con los productos y categorías de un sitio de comercio electrónico y genera por FPC.
Si usa este comando como a continuación-
redis-cli --scan --pattern 'key*' | xargs redis-cli del
O
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Elimina todas las teclas como ' xyz_category_fpc ' ( elimina las teclas 1, 2 y 3). Para eliminar otras 4, 5 y 6 teclas numéricas, use ' xyz_product_fpc ' en el comando anterior.
Si desea eliminar todo en Redis , siga estos comandos:
Con redis-cli:
Por ejemplo: - en su shell:
redis-cli flushall
redis-cli flushdb
redis-cli del
no es atómica.
La respuesta de @ itamar es genial, pero el análisis de la respuesta no me funcionó, especialmente. en el caso de que no se encuentren claves en un escaneo determinado. Una solución posiblemente más simple, directamente desde la consola:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
Esto también usa SCAN, que es preferible a KEYS en producción, pero no es atómico.
Acabo de tener el mismo problema. Almacené datos de sesión para un usuario en el formato:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
Entonces, cada entrada era un par clave-valor separado. Cuando se destruye la sesión, quería eliminar todos los datos de la sesión eliminando claves con el patrón session:sessionid:*
, pero redis no tiene esa función.
Lo que hice: almacené los datos de la sesión dentro de un hash . Me acabo de crear un hash con el identificador de hash session:sessionid
y luego empujo key-x
, key-y
, key-z
en esa almohadilla (para que no me importaba) y si no necesitas ese hash de más Me acaba de hacer una DEL session:sessionid
y todos los datos asociados a un determinado código hash se ha ido. DEL
es atómico y acceder a datos / escribir datos en el hash es O (1).
Creo que lo que podría ayudarlo es MULTI / EXEC / DISCARD . Si bien no es 100% equivalente a las transacciones , debería poder aislar las eliminaciones de otras actualizaciones.
FYI.
redis-cli
keys
(esto usa scan
)Tal vez solo necesite modificar caracteres en mayúscula.
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
Ejecutar en bash prompt
$ ./clear-redis-key.sh key_head_pattern
Es posible que otras respuestas no funcionen si su clave contiene caracteres especiales, Guide$CLASSMETADATA][1]
por ejemplo. Ajustar cada clave entre comillas asegurará que se eliminen correctamente:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
Una versión que usa SCAN en lugar de KEYS (como se recomienda para servidores de producción) y en --pipe
lugar de xargs.
Prefiero canalizar sobre xargs porque es más eficiente y funciona cuando sus claves contienen comillas u otros caracteres especiales que su shell intenta e interpreta. La sustitución de expresiones regulares en este ejemplo envuelve la clave entre comillas dobles y escapa a las comillas dobles dentro.
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
Esta no es una respuesta directa a la pregunta, pero dado que llegué aquí para buscar mis propias respuestas, compartiré esto aquí.
Si tiene decenas o cientos de millones de claves con las que tiene que coincidir, las respuestas que se dan aquí harán que Redis no responda por una cantidad significativa de tiempo (¿minutos?) Y posiblemente se bloquee debido al consumo de memoria (asegúrese de que se guarde en segundo plano patear en medio de su operación).
El siguiente enfoque es innegablemente feo, pero no encontré uno mejor. La atomicidad está fuera de discusión aquí, en este caso el objetivo principal es mantener a Redis activo y receptivo el 100% del tiempo. Funcionará perfectamente si tiene todas sus claves en una de las bases de datos y no necesita hacer coincidir ningún patrón, pero no puede usar http://redis.io/commands/FLUSHDB debido a su naturaleza de bloqueo.
La idea es simple: escriba un script que se ejecute en un bucle y utilice la operación O (1) como http://redis.io/commands/SCAN o http://redis.io/commands/RANDOMKEY para obtener claves, comprueba si haga coincidir el patrón (si lo necesita) y http://redis.io/commands/DEL ellos uno por uno.
Si hay una mejor manera de hacerlo, hágamelo saber, actualizaré la respuesta.
Ejemplo de implementación con randomkey en Ruby, como una tarea de rastrillo, un sustituto sin bloqueo de algo como 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
Se implementa de manera simple a través de la funcionalidad "Eliminar rama" en FastoRedis , solo seleccione la rama que desea eliminar.
Utilice este comando e intente:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
Probé la mayoría de los métodos mencionados anteriormente, pero no funcionaron para mí, después de algunas búsquedas encontré estos puntos:
-n [number]
del
pero si hay miles o millones de teclas, es mejor usar unlink
porque unlink no se bloquea mientras que del está bloqueando, para más información visite esta página unlink vs delkeys
son como del y está bloqueandoasí que usé este código para eliminar claves por patrón:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
Anuncio de ahora, puede usar un cliente redis y realizar primero SCAN (admite la coincidencia de patrones) y luego DEL cada tecla individualmente.
Sin embargo, hay un problema en el redis github oficial para crear un patrón de coincidencia del patrón aquí , ¡ve a mostrarle algo de amor si te resulta útil!
Apoyo todas las respuestas relacionadas con tener alguna herramienta o ejecutar la expresión Lua.
Una opción más de mi lado:
En nuestras bases de datos de producción y preproducción hay miles de claves. De vez en cuando necesitamos eliminar algunas claves (mediante alguna máscara), modificarlas según algunos criterios, etc. Por supuesto, no hay forma de hacerlo manualmente desde la CLI, especialmente si tiene un fragmento (512 dbs lógicos en cada físico).
Para este propósito, escribo la herramienta de cliente java que hace todo este trabajo. En caso de eliminación de claves, la utilidad puede ser muy simple, solo hay una clase allí:
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();
}
}
El siguiente comando funcionó para mí.
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
Spring RedisTemplate proporciona la funcionalidad. RedissonClient en la última versión ha desaprobado la funcionalidad "deleteByPattern".
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
keys
y delete
métodos.