Dalam Redis DB saya, saya memiliki sejumlah prefix:<numeric_id>
hash.
Terkadang saya ingin membersihkan semuanya secara atom. Bagaimana saya melakukan ini tanpa menggunakan mekanisme penguncian terdistribusi?
Dalam Redis DB saya, saya memiliki sejumlah prefix:<numeric_id>
hash.
Terkadang saya ingin membersihkan semuanya secara atom. Bagaimana saya melakukan ini tanpa menggunakan mekanisme penguncian terdistribusi?
Jawaban:
Dimulai dengan redis 2.6.0, Anda dapat menjalankan skrip lua, yang mengeksekusi secara atomis. Saya belum pernah menulis satu, tetapi saya pikir itu akan terlihat seperti ini
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Peringatan : Seperti yang dikatakan dokumen Redis , karena masalah kinerja,
keys
perintah tidak boleh digunakan untuk operasi reguler dalam produksi, perintah ini dimaksudkan untuk debugging dan operasi khusus. Baca lebih banyak
Lihat dokumentasi EVAL .
EVAL "local keys = redis.call('keys', ARGV[1]) \n for i=1,#keys,5000 do \n redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) \n end \n return keys" 0 prefix:*
del prefix:*
harus menjadi operasi mendasar: /
EVAL "return redis.call('del', 'defaultKey', unpack(redis.call('keys', ARGV[1])))" 0 prefix:*
Jalankan di bash:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
MEMPERBARUI
Baiklah saya mengerti. Bagaimana dengan cara ini: simpan awalan tambahan tambahan saat ini dan tambahkan ke semua kunci Anda. Sebagai contoh:
Anda memiliki nilai seperti ini:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
Ketika Anda perlu membersihkan data, Anda mengubah prefix_actuall terlebih dahulu (misalnya mengatur prefix_prefix_actuall = 3), jadi aplikasi Anda akan menulis data baru ke awalan kunci: 3: 1 dan awalan: 3: 2. Kemudian Anda dapat dengan aman mengambil nilai-nilai lama dari awalan: 2: 1 dan awalan: 2: 2 dan membersihkan kunci-kunci lama.
redis-cli KEYS "prefix:*" | xargs --delim='\n' redis-cli DEL
redis-cli -n 3 KEYS "prefix:*" | xargs redis-cli -n 3 DEL
Berikut ini adalah versi yang sepenuhnya berfungsi dan atom dari penghapusan wildcard diimplementasikan di Lua. Itu akan berjalan jauh lebih cepat daripada versi xargs karena jauh lebih sedikit jaringan bolak-balik, dan itu benar-benar atomik, memblokir permintaan lain terhadap redis sampai selesai. Jika Anda ingin menghapus kunci secara atomis pada Redis 2.6.0 atau lebih tinggi, ini jelas cara yang harus dilakukan:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
Ini adalah versi kerja dari ide @ mcdizzle dalam jawabannya untuk pertanyaan ini. Penghargaan untuk ide 100% jatuh padanya.
EDIT: Per komentar Kikito di bawah ini, jika Anda memiliki lebih banyak kunci untuk dihapus daripada membebaskan memori di server Redis Anda, Anda akan mengalami kesalahan "terlalu banyak elemen untuk dibuka" . Dalam hal ini, lakukan:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Seperti yang disarankan Kikito.
for _,k in ipairs(redis.call('keys', KEYS[1])) do redis.call('del', k) end
unpack
mengubah tabel dalam "daftar variabel independen" (bahasa lain menyebutnya explode
) tetapi jumlah maks tidak bergantung pada memori sistem; itu tetap di lua melalui LUAI_MAXSTACK
konstanta. Dalam Lua 5.1 & LuaJIT itu 8000 dan di Lua 5.2 adalah 100000. Opsi untuk loop direkomendasikan IMO.
EVAL
karena tidak menentukan terlebih dahulu kunci yang akan dioperasikan. Itu harus bekerja pada satu contoh tetapi jangan berharap itu bekerja dengan Redis Cluster.
Penafian: solusi berikut ini tidak memberikan atomicity.
Dimulai dengan v2.8 Anda benar - benar ingin menggunakan perintah SCAN, bukan KEYS [1]. Skrip Bash berikut menunjukkan penghapusan kunci berdasarkan pola:
#!/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 adalah perintah berbahaya yang berpotensi menghasilkan DoS. Berikut ini adalah kutipan dari halaman dokumentasinya:
Peringatan: pertimbangkan KUNCI sebagai perintah yang seharusnya hanya digunakan di lingkungan produksi dengan sangat hati-hati. Ini dapat merusak kinerja ketika dieksekusi terhadap database besar. Perintah ini dimaksudkan untuk debugging dan operasi khusus, seperti mengubah tata letak keyspace Anda. Jangan gunakan KUNCI dalam kode aplikasi reguler Anda. Jika Anda mencari cara untuk menemukan kunci di subset dari ruang kunci Anda, pertimbangkan untuk menggunakan set.
UPDATE: satu liner untuk efek dasar yang sama -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
-n 1
ke setiap redis-cli
doa:redis-cli -n 1 --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli -n 1 DEL
Bagi mereka yang kesulitan menguraikan jawaban lain:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
Ganti key:*:pattern
dengan pola Anda sendiri dan masukkan ini ke dalam redis-cli
dan Anda baik untuk pergi.
Credit lisco dari: http://redis.io/commands/del
Saya menggunakan perintah di bawah ini dalam redis 3.2.8
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
Anda dapat memperoleh bantuan lebih lanjut terkait dengan pencarian pola kunci dari sini: - https://redis.io/commands/keys . Gunakan pola gabus nyaman Anda sesuai kebutuhan Anda suka *YOUR_KEY_PREFIX*
atau YOUR_KEY_PREFIX??
atau yang lain.
Dan jika ada di antara Anda memiliki perpustakaan PHP Redis terintegrasi daripada fungsi di bawah ini akan membantu Anda.
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);
}
}
Terima kasih :)
Solusi @ mcdizle tidak berfungsi, hanya berfungsi untuk satu entri.
Ini berfungsi untuk semua kunci dengan awalan yang sama
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
Catatan: Anda harus mengganti 'awalan' dengan awalan kunci Anda ...
Anda juga dapat menggunakan perintah ini untuk menghapus kunci: -
Misalkan ada banyak jenis kunci di redis Anda seperti-
Ex- ' xyz_category_fpc ' di sini xyz adalah nama samaran , dan kunci-kunci ini terkait dengan produk dan kategori situs E-Commerce dan dihasilkan oleh FPC.
Jika Anda menggunakan perintah ini sebagai berikut-
redis-cli --scan --pattern 'key*' | xargs redis-cli del
ATAU
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Ini menghapus semua kunci seperti ' xyz_category_fpc ' (hapus kunci 1, 2 dan 3). Untuk menghapus kunci angka 4, 5 dan 6 lainnya gunakan ' xyz_product_fpc ' dalam perintah di atas.
Jika Anda ingin Hapus Semuanya di Redis , maka ikuti Perintah ini-
Dengan redis-cli:
Misalnya: - di shell Anda:
redis-cli flushall
redis-cli flushdb
redis-cli del
tidak atomik.
Jika Anda memiliki ruang dalam nama kunci, Anda dapat menggunakan ini di bash:
redis-cli keys "pattern: *" | xargs -L1 -I '$' echo '"$"' | xargs redis-cli del
@ itamar jawabannya bagus, tapi penguraian balasannya tidak bekerja untuk saya, esp. dalam kasus di mana tidak ada kunci yang ditemukan dalam pemindaian yang diberikan. Solusi yang mungkin lebih sederhana, langsung dari konsol:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
Ini juga menggunakan SCAN, yang lebih disukai daripada KEYS dalam produksi, tetapi tidak atomik.
Saya hanya punya masalah yang sama. Saya menyimpan data sesi untuk pengguna dalam format:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
Jadi, setiap entri adalah pasangan kunci-nilai yang terpisah. Ketika sesi dihancurkan, saya ingin menghapus semua data sesi dengan menghapus kunci dengan pola session:sessionid:*
- tetapi redis tidak memiliki fungsi seperti itu.
Apa yang saya lakukan: menyimpan data sesi dalam hash . Saya cukup membuat hash dengan id hash dari session:sessionid
dan kemudian saya mendorong key-x
, key-y
, key-z
di hash itu (agar tidak peduli dengan saya) dan jika saya tidak perlu bahwa hash lagi saya hanya melakukan DEL session:sessionid
dan semua data yang terkait dengan hash id hilang. DEL
adalah atom dan mengakses data / menulis data ke hash adalah O (1).
Saya pikir yang mungkin bisa membantu Anda adalah MULTI / EXEC / DISCARD . Meskipun tidak 100% setara dengan transaksi , Anda harus dapat mengisolasi penghapusan dari pembaruan lain.
FYI.
redis-cli
keys
(ini menggunakan scan
)Mungkin Anda hanya perlu memodifikasi huruf kapital.
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
Jalankan di bash prompt
$ ./clear-redis-key.sh key_head_pattern
Jawaban lain mungkin tidak berfungsi jika kunci Anda berisi karakter khusus - Guide$CLASSMETADATA][1]
misalnya. Memasukkan setiap kunci ke dalam tanda kutip akan memastikan mereka dihapus dengan benar:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
Versi menggunakan SCAN daripada KEYS (seperti yang direkomendasikan untuk server produksi) dan --pipe
bukan xargs.
Saya lebih suka menggunakan pipa lebih dari xargs karena lebih efisien dan berfungsi ketika kunci Anda berisi tanda kutip atau karakter khusus lain yang Anda coba coba dan tafsirkan. Substitusi pengganti dalam contoh ini membungkus kunci dalam tanda kutip ganda, dan lolos dari tanda kutip ganda di dalamnya.
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
Ini bukan jawaban langsung untuk pertanyaan itu, tetapi karena saya tiba di sini ketika mencari jawaban saya sendiri, saya akan membagikan ini di sini.
Jika Anda memiliki puluhan atau ratusan juta kunci yang harus Anda cocokkan, jawaban yang diberikan di sini akan menyebabkan Redis menjadi tidak responsif untuk jumlah waktu yang signifikan (menit?), Dan berpotensi crash karena konsumsi memori (pastikan, penyimpanan latar belakang akan tendang di tengah operasi Anda).
Pendekatan berikut tidak bisa disangkal jelek, tapi saya tidak menemukan yang lebih baik. Atomicity tidak dipertanyakan di sini, dalam hal ini tujuan utama adalah menjaga Redis tetap responsif dan 100% dari waktu. Ini akan berfungsi dengan baik jika Anda memiliki semua kunci di salah satu basis data dan Anda tidak perlu mencocokkan pola apa pun, tetapi tidak dapat menggunakan http://redis.io/commands/FLUSHDB karena itu memblokir alam.
Gagasannya sederhana: tulis skrip yang berjalan dalam satu lingkaran dan gunakan operasi O (1) seperti http://redis.io/commands/SCAN atau http://redis.io/commands/RANDOMKEY untuk mendapatkan kunci, periksa apakah mereka cocokkan polanya (jika Anda membutuhkannya) dan http://redis.io/commands/DEL satu per satu.
Jika ada cara yang lebih baik untuk melakukannya, beri tahu saya, saya akan memperbarui jawabannya.
Contoh implementasi dengan kunci acak di Ruby, sebagai tugas menyapu, pengganti non memblokir sesuatu seperti 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
Ini sederhana diimplementasikan melalui fungsi "Hapus cabang" di FastoRedis , cukup pilih cabang yang ingin Anda hapus.
Silakan gunakan perintah ini dan coba:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
Saya mencoba sebagian besar metode yang disebutkan di atas, tetapi mereka tidak berhasil bagi saya, setelah beberapa pencarian saya menemukan poin-poin ini:
-n [number]
del
tetapi jika ada ribuan atau jutaan kunci lebih baik digunakan unlink
karena pembatalan tautan adalah pemblokiran sementara del memblokir, untuk informasi lebih lanjut kunjungi halaman ini pembatalan tautan vs delkeys
seperti del dan memblokirjadi saya menggunakan kode ini untuk menghapus kunci berdasarkan pola:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
penghapusan massa atom orang miskin?
mungkin Anda bisa mengatur semuanya menjadi EXPIREAT pada detik yang sama - seperti beberapa menit di masa mendatang - dan kemudian menunggu hingga waktu itu dan melihat semuanya "merusak diri sendiri" pada saat yang sama.
tapi saya tidak begitu yakin bagaimana atomnya itu.
Iklan sekarang, Anda dapat menggunakan klien redis dan melakukan SCAN pertama (mendukung pencocokan pola) dan kemudian DEL setiap tombol secara individual.
Namun, ada masalah pada redis github resmi untuk membuat derai-pencocokan-del di sini , tunjukkan padanya beberapa cinta jika Anda merasa berguna!
Saya mendukung semua jawaban yang terkait dengan memiliki beberapa alat atau menjalankan ekspresi Lua.
Satu lagi opsi dari sisi saya:
Dalam basis data produksi dan pra-produksi kami ada ribuan kunci. Dari waktu ke waktu kita perlu menghapus beberapa kunci (dengan beberapa mask), memodifikasi dengan beberapa kriteria dll. Tentu saja, tidak ada cara untuk melakukannya secara manual dari CLI, terutama yang memiliki sharding (512 dbs logis dalam setiap fisik).
Untuk tujuan ini saya menulis alat klien java yang melakukan semua pekerjaan ini. Dalam kasus penghapusan kunci utilitas bisa sangat sederhana, hanya satu kelas di sana:
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();
}
}
Perintah di bawah ini bekerja untuk saya.
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
Spring RedisTemplate sendiri menyediakan fungsionalitas. RedissonClient dalam versi terbaru telah mencabut fungsi "deleteByPattern".
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
keys
dan delete
pemanggilan.