Как атомарно удалить ключи, соответствующие шаблону, используя Redis - PullRequest
525 голосов
/ 24 октября 2010

В моей базе данных Redis есть несколько prefix:<numeric_id> хешей.

Иногда я хочу очистить их все атомарно.Как мне сделать это без использования какого-либо распределенного механизма блокировки?

Ответы [ 21 ]

664 голосов
/ 24 октября 2010

Выполнить в bash:

redis-cli KEYS "prefix:*" | xargs redis-cli DEL

UPDATE

Хорошо, я понял. Как насчет этого: сохранить текущий дополнительный инкрементный префикс и добавить его ко всем вашим ключам. Например:

У вас есть такие значения:

prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10

Когда вам необходимо очистить данные, вы сначала изменяете prefix_actuall (например, установите prefix_prefix_actuall = 3), чтобы ваше приложение записывало новые данные в префикс ключей: 3: 1 и префикс: 3: 2. Тогда вы можете безопасно взять старые значения из префикса: 2: 1 и префикса: 2: 2 и очистить старые ключи.

396 голосов
/ 07 июня 2013

Начиная с 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 .

69 голосов
/ 10 июня 2013

Вот полностью рабочая и атомарная версия удаления с подстановочными знаками, реализованная в 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

Как предложил Кикито.

60 голосов
/ 01 мая 2014

Отказ от ответственности: следующее решение не не обеспечивает атомарность.

Начиная с v2.8, вы действительно хотите использовать SCAN команда вместо KEYS [1].Следующий скрипт Bash демонстрирует удаление ключей по шаблону:

#!/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 как команду, которую следует использовать только в производственных средах с особой осторожностью.Это может привести к снижению производительности при выполнении в больших базах данных.Эта команда предназначена для отладки и специальных операций, таких как изменение раскладки клавиатуры.Не используйте клавиши в вашем обычном коде приложения.Если вы ищете способ найти ключи в подмножестве своего пространства ключей, рассмотрите возможность использования наборов.

ОБНОВЛЕНИЕ: один вкладыш для того же базового эффекта -

$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
36 голосов
/ 19 марта 2014

Для тех, у кого возникли проблемы с анализом других ответов:

eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0

Замените key:*:pattern своим собственным шаблоном и введите его в redis-cli, и все готово.

Кредит Лиско от: http://redis.io/commands/del

35 голосов
/ 08 мая 2017

Я использую приведенную ниже команду в 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?? или любой другой.

И если кто-либо из вас интегрировал Redis PHP-библиотеку , то функция ниже поможет вам.

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);
            }
        }

Спасибо:)

17 голосов
/ 19 декабря 2014

@ Решение mcdizle не работает, оно работает только для одной записи.

Этот работает для всех ключей с одинаковым префиксом

EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*

Примечание: Вы должны заменить префикс своим префиксом ключа ...

17 голосов
/ 12 января 2017

Вы также можете использовать эту команду для удаления ключей: -

Предположим, в вашем Redis есть много типов ключей, например-

  1. 'xyz_category_fpc_12'
  2. FLUSHDB - Удаляет данные из базы данных CURRENT вашего соединения.
  3. FLUSHALL - Удаляет данные из ВСЕХ баз данных.

Например: - в вашей оболочке:

redis-cli flushall
redis-cli flushdb
12 голосов
/ 05 марта 2015

Если в имени ключа есть пробел, вы можете использовать его в bash:

redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del
10 голосов
/ 23 июня 2015

@ Итамар ответ велик, но разбор ответа не работал для меня, особенно. в случае, когда в данном сканировании не найдено ключей. Возможно более простое решение, прямо из консоли:

redis-cli -h HOST -p PORT  --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL

Здесь также используется SCAN, который предпочтительнее, чем KEYS в производстве, но не атомарный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...