Как атомарно удалить ключи, соответствующие шаблону, с помощью Redis

StackOverflow https://stackoverflow.com/questions/4006324

  •  25-09-2019
  •  | 
  •  

Вопрос

В моей базе данных Redis есть несколько 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 Documentation.

Другие советы

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

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

ОБНОВИТЬ

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

У вас есть такие ценности:

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 и очистить старые ключи.

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

РЕДАКТИРОВАТЬ: За комментарий Kickito ниже, если у вас есть больше ключей для удаления, чем бесплатная память на вашем сервере Redis, вы столкнетесь с «Слишком много элементов, чтобы распаковать ошибку». Отказ В этом случае делать:

for _,k in ipairs(redis.call('keys', ARGV[1])) do 
    redis.call('del', k) 
end

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

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

Начиная с V2.8 Вы В самом деле хочу использовать Сканирование команда вместо клавиш [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] Ключи Это опасная команда, которая может потенциально привести к доне. Ниже приведена цитата из своей страницы документации:

Предупреждение: Рассмотрим ключи в качестве команды, которая должна использоваться только в производственных средах с чрезвычайной осторожностью. Это может разрушить производительность, когда он выполняется против больших баз данных. Эта команда предназначена для отладки и специальных операций, таких как изменение макета Keyspace. Не используйте ключи в вашем регулярном коде приложения. Если вы ищете способ найти клавиши в подмножестве вашего клавиатуры, рассмотрите возможность использования наборов.

ОБНОВИТЬ: один вкладыш для того же основного эффекта -

$ 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 И ты хорош, чтобы пойти.

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

Я использую приведенную ниже команду в Redis 3.2.8

redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL

Вы можете получить больше помощи, связанные с клавишами поиска шаблонов отсюда: - https://dedis.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);
            }
        }

Спасибо :)

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

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

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

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

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

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

  1. 'xyz_category_fpc_12'
  2. 'xyz_category_fpc_245'
  3. 'xyz_category_fpc_321'
  4. 'xyz_product_fpc_876'
  5. 'xyz_product_fpc_302'
  6. 'xyz_product_fpc_01232'

Бывший- 'xyz_category_fpc.' здесь сми это Название сайта, И эти ключи связаны с продуктами и категориями сайта электронной коммерции и генерируются FPC.

Если вы используете эту команду как ниже-

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-Cli:

  1. Потрясающий - Удаляет данные из текущей базы данных вашей связи.
  2. Прорезаться - Удаляет данные из всех баз данных.

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

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

Это также использует сканирование, которое предпочтительнее ключей в производстве, но не атомно.

У меня только что была такая же проблема. Я сохранил данные сеанса для пользователя в формате:

session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z

Итак, каждая запись была отдельной парой ключа. Когда сеанс уничтожен, я хотел удалить все данные сеанса, удаляя ключи с рисунком session:sessionid:* - Но Redis не имеет такой функции.

Что я сделал: сохранить данные сеанса в пределах хэш. Отказ Я просто создаю хеш с хэш-идентификатором session:sessionid а потом я нажимаю key-x, key-y, key-z в этом хеш (порядок не имеет значения для меня), и если бы мне больше не нуждаюсь в этом хэш, я просто делаю DEL session:sessionid И все данные, связанные с этим хеш-идентификатором, ушли. DEL Является ли атомные и доступ к данным / записи / записи в хеш - это O (1).

FYI.

  • только с помощью bash и 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

$ ./clear-redis-key.sh key_head_pattern

Я думаю, что может помочь вам Multi / Exec / Discard. Отказ В то время как не 100% эквивалент транзакций, вы должны быть в состоянии изолировать удаления от других обновлений.

Это просто реализовано через функциональность «Удалить ветвь» в Fastoredis, Просто выберите ветку, которую вы хотите удалить.

enter image description here

Пожалуйста, используйте эту команду и попробуйте:

redis-cli --raw keys "$PATTERN" | xargs redis-cli del

Версия, использующая сканирование, а не ключей (как рекомендуется для производственных серверов) и --pipe а не ксарка.

Я предпочитаю трубу через Xargs, потому что это более эффективно и работает, когда ваши клавиши содержат цитаты или другие специальные символы, которые ваша оболочка с попыткой интерпретации. Подстановка Regeex в этом примере набирает ключ в двойных кавычках и убегает в любые двойные кавычки внутри.

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

Это не прямой ответ на вопрос, но поскольку я получил сюда при поиске моих собственных ответов, я поделюсь этим здесь.

Если у вас есть десятки или сотни миллионов ключей, которые вы должны соответствовать, приведенные здесь ответы приведут к Redis не отзывчивым в течение значительного количества времени (минут?), А потенциально аварийно из-за расхода памяти (будьте уверены, пинайте в середине вашей операции).

Следующий подход несомненно, но я не нашел лучшего. Атомарность не имеет вопроса здесь, в этом случае главная цель - продолжать рады и отзывчиваться в 100% времени. Он будет работать идеально, если у вас есть все ваши ключи в одной из баз данных, и вам не нужно соответствовать любому шаблону, но не может использовать http://dedis.io/commands/flushdb. из-за блокировки природы.

Идея проста: напишите сценарий, который работает в цикле и использует операцию O (1), как http://redis.io/commands/scan. или http://redis.io/commands/randomkey Чтобы получить ключи, проверяет, сопоставят ли они шаблон (если вам это нужно) и http://redis.io/commands/del. их один за другим.

Если есть лучший способ сделать это, пожалуйста, дайте мне знать, я обновит ответ.

Пример реализации с Randomkey в Ruby, как задача грабля, не блокирующая замена чего-то вроде 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

Я попробовал большую часть методов, упомянутых выше, но они не работали для меня, после того, как некоторые поиски я нашел эти очки:

  • Если у вас есть более одной БД на Redis, вы должны определить базу данных, используя -n [number]
  • Если у вас есть несколько клавиш del Но если есть тысячи или миллионы ключей, лучше использовать unlink потому что UniNeble не блокируется Пока Del блокирует, для получения дополнительной информации посетите эту страницу Unlink vs del.
  • также keys как дель и блокируют

Поэтому я использовал этот код для удаления клавиш по образцу:

 redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink 

Я поддерживаю все ответы, связанные с некоторым инструментом или выполнять выражение LUA.

Еще один вариант от моей стороны:

В наших производственных и предварительно производственных базах данных есть тысячи ключей. Время во времени нам нужно удалить некоторые ключи (по какой-то маске), изменять некоторые критерии и т. Д. Конечно, нет способа сделать это вручную из CLI, особенно кардирование (512 логических DBS в каждом физическом).

Для этого я пишу Java Client Tool, который делает всю эту работу. В случае удаления ключей утилита может быть очень простым, только один класс там:

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

}

Ниже команда работала для меня.

redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL

AD теперь вы можете использовать клиент Redis и выполнить первое сканирование (поддерживает сопоставление шаблонов), а затем DEL каждая клавиша индивидуально.

Тем не менее, есть проблема на официальном redis Github для создания скороговорки-матча-дель здесь, Иди показать это немного любви, если вы найдете это полезным!

Атомное массовое удаление бедняка?

возможно, вы могли бы установить для них EXPIREAT в одну и ту же секунду - например, через несколько минут в будущем - а затем подождать до этого времени и увидеть, как все они «самоуничтожаются» одновременно.

но я не совсем уверен, насколько это будет атомарно.

Само повторное распределение весны обеспечивает функциональность. RedissonClient в последней версии обесценил функциональность «DELETEBYPATTRNN».

Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top