كيفية حذف المفاتيح المطابقة للنمط ذريًا باستخدام Redis

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

  •  25-09-2019
  •  | 
  •  

سؤال

في 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_*]

انظر وثائق تقييم.

نصائح أخرى

تنفيذ في باش:

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 ٪ يذهب إليه.

تعديل: لكل تعليق Kikito أدناه ، إذا كان لديك المزيد من المفاتيح للحذف من الذاكرة المجانية في خادم Redis الخاص بك ، فستواجه إلى "الكثير من العناصر التي لا يمكن تفريغها". في هذه الحالة ، افعل:

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

كما اقترح كيكيتو.

إخلاء المسؤولية: الحل التالي لا توفير الذرة.

بدءا من v2.8 أنت هل حقا تريد استخدام مسح الأمر بدلاً من المفاتيح [1]. يوضح البرنامج النصي التالي باش حذف المفاتيح حسب النمط:

#!/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] مفاتيح هو أمر خطير يمكن أن يؤدي إلى DOS. فيما يلي اقتباس من صفحة الوثائق الخاصة به:

تحذير: النظر في المفاتيح كأمر الذي يجب استخدامه فقط في بيئات الإنتاج بعناية فائقة. قد يدمر الأداء عند تنفيذه ضد قواعد البيانات الكبيرة. هذا الأمر مخصص لتصحيح الأخطاء والعمليات الخاصة ، مثل تغيير تخطيط الفضاء. لا تستخدم المفاتيح في رمز التطبيق العادي. إذا كنت تبحث عن طريقة للعثور على مفاتيح في مجموعة فرعية من مساحة المفاتيح الخاصة بك ، ففكر في استخدام المجموعات.

تحديث: بطانة واحدة لنفس التأثير الأساسي -

$ 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://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);
            }
        }

شكرًا لك :)

@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' هنا XYZ هو اسم الموقع, ، وترتبط هذه المفاتيح بمنتجات وفئات موقع التجارة الإلكترونية وتولدها 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. Flushdb - يزيل البيانات من قاعدة البيانات الحالية لاتصالك.
  2. Flushall - يزيل البيانات من جميع قواعد البيانات.

على سبيل المثال:- في قشرتك:

redis-cli flushall
redis-cli flushdb

إذا كان لديك مساحة باسم المفاتيح ، فيمكنك استخدام هذا في Bash:

redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del

@إجابة Itamar رائعة ، لكن تحليل الرد لم يكن يعمل بالنسبة لي ، esp. في حالة عدم وجود مفاتيح موجودة في فحص معين. حل ربما أبسط ، مباشرة من وحدة التحكم:

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

لعِلمِكَ.

  • فقط باستخدام باش و redis-cli
  • عدم استخدام keys (هذا يستخدم 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

ركض في مطالبة باش

$ ./clear-redis-key.sh key_head_pattern

أعتقد أن ما قد يساعدك هو متعددة/exec/تجاهل. بينما لا 100 ٪ ما يعادل المعاملات, ، يجب أن تكون قادرًا على عزل الحذف عن التحديثات الأخرى.

يتم تنفيذها بسيطًا عبر وظيفة "إزالة الفرع" في فاستوريس, ، فقط حدد الفرع الذي تريد إزالته.

enter image description here

الرجاء استخدام هذا الأمر ومحاولة:

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

نسخة باستخدام المسح بدلاً من المفاتيح (كما هو موصى بها لخوادم الإنتاج) و --pipe بدلا من xargs.

أفضل الأنابيب على XARGS لأنها أكثر كفاءة وتعمل عندما تحتوي مفاتيحك على علامات اقتباس أو شخصيات خاصة أخرى تفسرها وتفسيرها. يلف استبدال Regex في هذا المثال المفتاح في عروض الأسعار المزدوجة ، ويهرب من أي اقتباسات مزدوجة في الداخل.

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 لفترة طويلة من الوقت (دقائق؟)، ومن المحتمل أن يتعطل بسبب استهلاك الذاكرة (تأكد من أن حفظ الخلفية سيتم ركلة في منتصف عمليتك).

النهج التالي قبيح بلا شك، لكنني لم أجد طريقة أفضل.الذرية غير واردة هنا، في هذه الحالة الهدف الرئيسي هو الحفاظ على Redis نشيطًا ومستجيبًا بنسبة 100% من الوقت.ستعمل بشكل مثالي إذا كانت لديك جميع مفاتيحك في إحدى قواعد البيانات ولا تحتاج إلى مطابقة أي نمط، ولكن لا يمكنك استخدامها http://redis.io/commands/FLUSHDB لأنه يحجب الطبيعة.

الفكرة بسيطة:اكتب برنامجًا نصيًا يتم تشغيله في حلقة ويستخدم عملية O(1) مثل http://redis.io/commands/SCAN أو http://redis.io/commands/RANDOMKEY للحصول على المفاتيح، تحقق مما إذا كانت تطابق النمط (إذا كنت في حاجة إليه) و http://redis.io/commands/DEL لهم واحدا تلو الآخر.

إذا كانت هناك طريقة أفضل للقيام بذلك، فيرجى إبلاغي بذلك، وسأقوم بتحديث الإجابة.

مثال على التنفيذ باستخدام مفتاح عشوائي في روبي، كمهمة أشعل النار، بديل غير محظور لشيء مثل 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 لان إلغاء التمييز غير محظور أثناء حظر ديل ، لمزيد من المعلومات ، تفضل بزيارة هذه الصفحة Unlink vs del
  • ايضا keys مثل ديل وتمنع

لذلك استخدمت هذا الرمز لحذف المفاتيح حسب النمط:

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

أنا أؤيد جميع الإجابات المتعلقة بوجود بعض الأدوات أو تنفيذ تعبير LUA.

خيار آخر من جانبي:

في قواعد بيانات الإنتاج والإنتاج قبل الإنتاج ، هناك الآلاف من المفاتيح. من الوقت لآخر نحتاج إلى حذف بعض المفاتيح (بواسطة بعض القناع) ، والتعديل حسب بعض المعايير وما إلى ذلك ، بالطبع ، لا توجد طريقة للقيام بذلك يدويًا من CLI ، خاصةً وجود Sharding (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();
    }

}

كان الأمر أدناه يعمل بالنسبة لي.

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

إعلان الآن ، يمكنك استخدام عميل redis وإجراء المسح الأول (يدعم مطابقة الأنماط) ثم DEL كل مفتاح بشكل فردي.

ومع ذلك ، هناك مشكلة في Redis Github الرسمية لإنشاء تأخير مطابقة هنا, ، اذهب إلى إظهار بعض الحب إذا وجدت أنه مفيد!

تحرر الكتلة الذرية للرجل الفقير؟

ربما يمكنك تعيينهم جميعًا على انتهاء نفس الثانية - مثل بضع دقائق في المستقبل - ثم انتظر حتى ذلك الوقت ورؤيتهم جميعًا "تدمير الذات" في نفس الوقت.

لكنني لست متأكدًا حقًا كيف سيكون ذلك ذريًا.

الربيع Redistemplate نفسه يوفر الوظيفة. قام RedissonClient في أحدث إصدار بإهمال وظيفة "DeleteBypattern".

Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top