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

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

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

Ответы [ 21 ]

8 голосов
/ 18 декабря 2010

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

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).

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

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
5 голосов
/ 24 октября 2010

Я думаю, что вам может помочь MULTI / EXEC / DISCARD . Хотя не 100% эквивалент транзакций , вы должны иметь возможность изолировать удаления от других обновлений.

4 голосов
/ 29 ноября 2018

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

redis-cli --raw keys "$PATTERN" | xargs redis-cli del
4 голосов
/ 05 января 2018

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

enter image description here

2 голосов
/ 26 июня 2017

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

Я предпочитаю pipe вместо 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
2 голосов
/ 22 февраля 2016

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

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

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

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

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

Пример реализации с помощью randomkey в 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
0 голосов
/ 11 июля 2019

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

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

, поэтому я использовал этот код для удаленияключи по шаблону:

 redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink 
0 голосов
/ 13 марта 2014

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

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

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

0 голосов
/ 01 сентября 2016

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

Еще одна опция с моей стороны:

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

Для этого я пишу клиентский инструмент 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();
    }

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