В моей Redis DB у меня есть ряд хешей prefix:<numeric_id>
.
Иногда я хочу их продуть атомарно. Как это сделать без использования какого-либо распределенного механизма блокировки?
В моей Redis DB у меня есть ряд хешей prefix:<numeric_id>
.
Иногда я хочу их продуть атомарно. Как это сделать без использования какого-либо распределенного механизма блокировки?
Начиная с redis 2.6.0, вы можете запускать сценарии lua, которые выполняются атомарно. Я никогда не писал, но я думаю, что это будет выглядеть примерно так
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Смотрите документацию EVAL.
Выполнить в bash:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
UPDATE
Хорошо, я понял. Как насчет этого способа: сохраните текущий дополнительный инкрементный префикс и добавьте его ко всем вашим ключам. Например:
У вас есть такие значения:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
Когда вам нужно очистить данные, вы сначала меняете prefix_actuall (например, set prefix_prefix_actuall = 3), поэтому ваше приложение будет записывать новые данные в префикс ключей: 3: 1 и префикс: 3: 2. Затем вы можете безопасно взять старые значения из префикса: 2: 1 и префикс: 2: 2 и очистить старые ключи.
Здесь полностью работающая и атомарная версия удаленной замены, реализованная в Lua. Он будет работать намного быстрее, чем версия xargs из-за гораздо меньшей загрузки сети и полностью атомарной, блокируя любые другие запросы против redis до тех пор, пока он не завершится. Если вы хотите атомически удалить ключи на Redis 2.6.0 или выше, это определенно путь:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
Это рабочая версия идеи @mcdizzle в его ответе на этот вопрос. Кредит за идею 100% идет к нему.
РЕДАКТИРОВАТЬ: В комментарии на Kikito ниже, если у вас есть больше ключей для удаления, чем свободная память на сервере Redis, вы столкнетесь с "слишком много элементов для распаковки" . В этом случае выполните:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Как предложил Кикито.
Отказ от ответственности: следующее решение не предоставляет атомарность.
Начиная с v2.8 вы действительно хотите использовать команду SCAN вместо KEYS [1]. Следующий Bash script демонстрирует удаление ключей по шаблону:
#!/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 - опасная команда, которая может привести к DoS. Ниже приведена цитата со страницы документации:
Предупреждение: рассмотрите KEYS как команду, которая должна использоваться исключительно в производственных средах с особой осторожностью. Он может испортить производительность, когда он выполняется против больших баз данных. Эта команда предназначена для отладки и специальных операций, таких как изменение макета вашего ключа. Не используйте KEYS в вашем обычном коде приложения. Если вы ищете способ поиска ключей в подмножестве своего пространства ключей, подумайте об использовании наборов.
UPDATE: один лайнер для одного и того же базового эффекта -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
Для тех, у кого были проблемы с разбором других ответов:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
Замените key:*:pattern
вашим собственным шаблоном и введите его в redis-cli
и все redis-cli
.
Кредит Лиско от: http://redis.io/commands/del
Я использую команду ниже в redis 3.2.8
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
Вы можете получить дополнительную помощь, связанную с поиском шаблонов клавиш отсюда: - https://redis.io/commands/keys. Используйте свой удобный шаблон в стиле глобуса в соответствии с вашим требованием, например *YOUR_KEY_PREFIX*
или YOUR_KEY_PREFIX??
или любым другим.
И если у вас есть интегрированная библиотека PHP Redis, то ниже вам поможет функция.
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);
}
}
Спасибо:)
@mcdizle не работает, оно работает только для одной записи.
Этот файл работает для всех ключей с одним и тем же префиксом
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
Примечание. Вы должны заменить префикс на свой префикс ключа...
Вы также можете использовать эту команду для удаления ключей: -
Предположим, что в вашем Redis есть много типов ключей like-
Ex- " xyz_category_fpc " здесь xyz - это имя сайта, и эти ключи относятся к продуктам и категориям сайта электронной коммерции и генерируются FPC.
Если вы используете эту команду как below-
redis-cli --scan --pattern 'key*' | xargs redis-cli del
ИЛИ ЖЕ
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Он удаляет все ключи, такие как " xyz_category_fpc " (удаляет ключи 1, 2 и 3). Для удаления других 4, 5 и 6 цифровых клавиш используйте команду " xyz_product_fpc " в приведенной выше команде.
Если вы хотите удалить все в Redis, то следуйте этим Commands-
С редис-кли:
Например: - в вашей оболочке:
redis-cli flushall
redis-cli flushdb
Если у вас есть пробел в имени клавиш, вы можете использовать его в bash:
redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del
Ответ на @itamar велик, но разбор ответа не работал у меня, особенно. в случае отсутствия ключей, обнаруженных в данном сканировании. Возможно, более простое решение, прямо с консоли:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
Это также использует SCAN, который предпочтительнее KEYS в производстве, но не является атомарным.
У меня была такая же проблема. Я сохранил данные сеанса для пользователя в формате:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
Таким образом, каждая запись представляла собой отдельную пару "ключ-значение". Когда сеанс уничтожен, я хотел удалить все данные сеанса, удалив ключи с помощью шаблона session:sessionid:*
, но redis не имеет такой функции.
Что я сделал: сохраните данные сеанса в hash. Я просто создаю хэш с хеш-идентификатором session:sessionid
, а затем нажимаю key-x
, key-y
, key-z
в этом хэше (для меня это не имеет значения), и если мне не нужен этот хеш, я просто делаю a DEL session:sessionid
, и все данные, связанные с этим идентификатором хэша, исчезли. DEL
является атомарным и доступ к данным/записи данных в хеш-это O (1).
Я думаю, что вам может помочь MULTI/EXEC/DISCARD. Хотя 100% эквивалент транзакций, вы должны иметь возможность изолировать удаленные файлы от других обновлений.
FYI.
redis-cli
keys
(используется scan
)Возможно, вам нужно только изменить символы капитала.
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
Запуск в bash prompt
$ ./clear-redis-key.sh key_head_pattern
Это просто реализуется через функцию "Удалить ветку" в FastoRedis, просто выберите ветку, которую вы хотите удалить.
Пожалуйста, используйте эту команду и попробуйте:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
Это не прямой ответ на вопрос, но поскольку я пришел сюда, когда искал свои собственные ответы, я поделюсь этим здесь.
Если у вас есть десятки или сотни миллионов ключей, которые вам нужно сопоставить, ответы, приведенные здесь, заставят Redis не реагировать на значительное количество времени (минут?) и потенциально сбой из-за потребления памяти (обязательно, фоновое сохранение начнется в середине вашей операции).
Следующий подход, несомненно, некрасиво, но я не нашел лучшего. Атомность здесь не может быть и речи, в этом случае главная цель - сохранить Redis до 100% времени. Он будет работать отлично, если у вас есть все ваши ключи в одной из баз данных, и вам не нужно сопоставлять какой-либо шаблон, но не можете использовать http://redis.io/commands/FLUSHDB из-за того, что он блокирует природу.
Идея проста: напишите script, который выполняется в цикле и использует операцию O (1), например http://redis.io/commands/SCAN или http://redis.io/commands/RANDOMKEY, чтобы получить ключи, проверяет, соответствуют ли они шаблону (если вам это нужно) и http://redis.io/commands/DEL их по одному.
Если есть лучший способ сделать это, пожалуйста, дайте мне знать, я обновлю ответ.
Пример реализации со случайным ключом в Ruby, как задача rake, неблокирующая замена чего-то вроде 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
Версия, использующая SCAN, а не KEYS (как рекомендовано для производственных серверов) и --pipe
, а не xargs.
Я предпочитаю использовать трубку поверх xargs, потому что она более эффективна и работает, когда ваши ключи содержат кавычки или другие специальные символы, которые ваша оболочка пытается и интерпретирует. Подстановка регулярного выражения в этом примере обертывает ключ в двойные кавычки и исключает любые двойные кавычки внутри.
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
Я поддерживаю все ответы, связанные с наличием какого-либо инструмента или выполнением выражения Lua.
Еще один вариант с моей стороны:
В наших производственных и предварительных базах данных есть тысячи ключей. Время от времени нам нужно удалить некоторые ключи (по какой-то маске), изменить по некоторым критериям и т.д. Конечно, нет способа сделать это вручную из CLI, особенно имея осколки (512 логических dbs в каждом физическом).
С этой целью я пишу java-клиентский инструмент, который делает все это. В случае удаления ключей утилита может быть очень простой, только один класс:
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();
}
}
Я попробовал большинство методов, упомянутых выше, но они не спомогли мне, после некоторых поисков я нашел следующие пункты:
-n [number]
del
но если есть тысячи или миллионы ключей, лучше использовать unlink
потому что unlink неблокирует, а del блокирует, для получения дополнительной информации посетите эту страницу unlink vs delkeys
как дель и блокируетпоэтому я использовал этот код для удаления ключей по шаблону:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
бедный человек атомная масса-удалить?
Возможно, вы могли бы установить их все в EXPIREAT за ту же секунду - например, через несколько минут в будущем, - а затем подождать до этого времени и одновременно увидеть все "самоуничтожение".
но я не уверен, насколько это будет атом.
Spring Функция RedisTemplate обеспечивает функциональность. В последней версии RedissonClient устарела функциональность "deleteByPattern".
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
redis-cli keys "*prefix*"
работа для меня