Trong Redis DB của tôi, tôi có một số giá trị prefix:<numeric_id>
băm.
Đôi khi tôi muốn thanh lọc tất cả chúng một cách nguyên tử. Làm thế nào để tôi làm điều này mà không sử dụng một số cơ chế khóa phân tán?
Trong Redis DB của tôi, tôi có một số giá trị prefix:<numeric_id>
băm.
Đôi khi tôi muốn thanh lọc tất cả chúng một cách nguyên tử. Làm thế nào để tôi làm điều này mà không sử dụng một số cơ chế khóa phân tán?
Câu trả lời:
Bắt đầu với redis 2.6.0, bạn có thể chạy các tập lệnh lua, thực thi nguyên tử. Tôi chưa bao giờ viết một cái, nhưng tôi nghĩ nó sẽ trông giống như thế này
EVAL "return redis.call('del', unpack(redis.call('keys', ARGV[1])))" 0 prefix:[YOUR_PREFIX e.g delete_me_*]
Cảnh báo : Như tài liệu Redis nói, vì các hiệu suất làm việc,
keys
lệnh không nên sử dụng cho các hoạt động thường xuyên trong sản xuất, lệnh này được dùng để gỡ lỗi và các hoạt động đặc biệt. đọc thêm
Xem tài liệu 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:*
là một hoạt động cơ bản: /
EVAL "return redis.call('del', 'defaultKey', unpack(redis.call('keys', ARGV[1])))" 0 prefix:*
Thực thi trong bash:
redis-cli KEYS "prefix:*" | xargs redis-cli DEL
CẬP NHẬT
Ok, tôi hiểu. Điều gì về cách này: lưu trữ tiền tố gia tăng bổ sung hiện tại và thêm nó vào tất cả các khóa của bạn. Ví dụ:
Bạn có các giá trị như thế này:
prefix_prefix_actuall = 2
prefix:2:1 = 4
prefix:2:2 = 10
Khi bạn cần lọc dữ liệu, trước tiên bạn thay đổi prefix_actuall (ví dụ: đặt prefix_prefix_actuall = 3), vì vậy ứng dụng của bạn sẽ ghi dữ liệu mới vào tiền tố khóa: 3: 1 và tiền tố: 3: 2. Sau đó, bạn có thể lấy các giá trị cũ một cách an toàn từ tiền tố: 2: 1 và tiền tố: 2: 2 và thanh lọc các khóa cũ.
redis-cli KEYS "prefix:*" | xargs --delim='\n' redis-cli DEL
redis-cli -n 3 KEYS "prefix:*" | xargs redis-cli -n 3 DEL
Đây là phiên bản hoàn toàn hoạt động và nguyên tử của việc xóa ký tự đại diện được thực hiện ở Lua. Nó sẽ chạy nhanh hơn nhiều so với phiên bản xargs do mạng qua lại ít hơn nhiều và nó hoàn toàn nguyên tử, chặn mọi yêu cầu khác chống lại redis cho đến khi kết thúc. Nếu bạn muốn xóa các khóa trên Redis 2.6.0 trở lên, đây chắc chắn là cách nên làm:
redis-cli -n [some_db] -h [some_host_name] EVAL "return redis.call('DEL', unpack(redis.call('KEYS', ARGV[1] .. '*')))" 0 prefix:
Đây là phiên bản hoạt động của ý tưởng của @ mcdizzle trong câu trả lời của anh ấy cho câu hỏi này. Tín dụng cho ý tưởng 100% đi vào anh ta.
EDIT: Theo nhận xét của Kikito bên dưới, nếu bạn có nhiều khóa cần xóa hơn bộ nhớ trống trong máy chủ Redis, bạn sẽ gặp phải lỗi "quá nhiều yếu tố để giải nén" . Trong trường hợp đó, hãy làm:
for _,k in ipairs(redis.call('keys', ARGV[1])) do
redis.call('del', k)
end
Như Kikito đề nghị.
for _,k in ipairs(redis.call('keys', KEYS[1])) do redis.call('del', k) end
unpack
biến đổi một bảng trong một "danh sách các biến độc lập" (các ngôn ngữ khác gọi đó explode
) nhưng số lượng tối đa không phụ thuộc vào bộ nhớ syste; nó cố định trong lua qua LUAI_MAXSTACK
hằng số. Trong Lua 5.1 & LuaJIT, nó là 8000 và trong Lua 5.2 là 100000. Tùy chọn vòng lặp for được khuyến nghị IMO.
EVAL
vì nó không chỉ định trước các khóa mà nó sẽ hoạt động. Nó nên hoạt động trong một trường hợp duy nhất nhưng đừng hy vọng nó hoạt động với Redis Cluster.
Tuyên bố miễn trừ trách nhiệm: giải pháp sau đây không cung cấp tính nguyên tử.
Bắt đầu với v2.8, bạn thực sự muốn sử dụng lệnh SCAN thay vì KEYS [1]. Kịch bản Bash sau đây thể hiện việc xóa các khóa theo mẫu:
#!/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 là một lệnh nguy hiểm có khả năng dẫn đến DoS. Sau đây là một trích dẫn từ trang tài liệu của nó:
Cảnh báo: coi KEYS là một lệnh chỉ nên được sử dụng trong môi trường sản xuất hết sức cẩn thận. Nó có thể làm hỏng hiệu suất khi nó được thực thi đối với các cơ sở dữ liệu lớn. Lệnh này được dùng để gỡ lỗi và các hoạt động đặc biệt, chẳng hạn như thay đổi bố cục không gian phím của bạn. Không sử dụng KEYS trong mã ứng dụng thông thường của bạn. Nếu bạn đang tìm cách để tìm các khóa trong một tập hợp con của không gian khóa, hãy xem xét sử dụng các bộ.
CẬP NHẬT: một lớp lót cho cùng một hiệu ứng cơ bản -
$ redis-cli --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli DEL
-n 1
vào mỗi lần redis-cli
gọi:redis-cli -n 1 --scan --pattern "*:foo:bar:*" | xargs -L 100 redis-cli -n 1 DEL
Đối với những người gặp khó khăn khi phân tích các câu trả lời khác:
eval "for _,k in ipairs(redis.call('keys','key:*:pattern')) do redis.call('del',k) end" 0
Thay thế key:*:pattern
bằng mô hình của riêng bạn và nhập này vào redis-cli
và bạn tốt để đi.
Tín dụng lisco từ: http://redis.io/commands/del
Tôi đang sử dụng lệnh dưới đây trong redis 3.2.8
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
Bạn có thể nhận thêm trợ giúp liên quan đến tìm kiếm mẫu khóa từ đây: - https://redis.io/commands/keys . Sử dụng mô hình thuận tiện glob-phong cách của bạn theo yêu cầu của bạn như *YOUR_KEY_PREFIX*
hoặc YOUR_KEY_PREFIX??
hoặc bất kỳ khác.
Và nếu bất kỳ ai trong số các bạn đã tích hợp thư viện Redis PHP thì chức năng dưới đây sẽ giúp bạn.
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);
}
}
Cảm ơn bạn :)
Giải pháp của @ mcdizle không hoạt động, nó chỉ hoạt động cho một mục nhập.
Cái này hoạt động cho tất cả các khóa có cùng tiền tố
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
Lưu ý: Bạn nên thay thế 'tiền tố' bằng tiền tố chính ...
Bạn cũng có thể sử dụng lệnh này để xóa các phím: -
Giả sử có nhiều loại khóa trong redis của bạn như-
Ex- ' xyz_carget_fpc ' ở đây xyz là một tên trang web và các khóa này có liên quan đến các sản phẩm và danh mục của trang web Thương mại điện tử và được tạo bởi FPC.
Nếu bạn sử dụng lệnh này như dưới đây-
redis-cli --scan --pattern 'key*' | xargs redis-cli del
HOẶC LÀ
redis-cli --scan --pattern 'xyz_category_fpc*' | xargs redis-cli del
Nó xóa tất cả các khóa như ' xyz_carget_fpc ' (xóa các phím 1, 2 và 3). Để xóa các phím số 4, 5 và 6 khác, hãy sử dụng ' xyz_product_fpc ' trong lệnh trên.
Nếu bạn muốn xóa mọi thứ trong Redis , hãy làm theo các lệnh này-
Với redis-cli:
Ví dụ: - trong vỏ của bạn:
redis-cli flushall
redis-cli flushdb
redis-cli del
không phải là nguyên tử.
Câu trả lời của @ itamar là tuyệt vời, nhưng việc phân tích cú pháp trả lời không hiệu quả với tôi, đặc biệt. trong trường hợp không tìm thấy khóa nào trong một lần quét nhất định. Một giải pháp có thể đơn giản hơn, trực tiếp từ bảng điều khiển:
redis-cli -h HOST -p PORT --scan --pattern "prefix:*" | xargs -n 100 redis-cli DEL
Điều này cũng sử dụng SCAN, tốt hơn so với KEYS trong sản xuất, nhưng không phải là nguyên tử.
tôi chỉ có cùng một vấn đề. Tôi đã lưu trữ dữ liệu phiên cho người dùng ở định dạng:
session:sessionid:key-x - value of x
session:sessionid:key-y - value of y
session:sessionid:key-z - value of z
Vì vậy, mỗi mục nhập là một cặp khóa-giá trị riêng biệt. Khi phiên bị hủy, tôi muốn xóa tất cả dữ liệu phiên bằng cách xóa các khóa có mẫu session:sessionid:*
- nhưng redis không có chức năng như vậy.
Những gì tôi đã làm: lưu trữ dữ liệu phiên trong một hàm băm . Tôi chỉ cần tạo một hash với id hash của session:sessionid
và sau đó tôi đẩy key-x
, key-y
, key-z
trong băm mà (thứ tự không quan trọng với tôi) và nếu tôi không cần điều đó băm nữa tôi chỉ làm một DEL session:sessionid
và tất cả các dữ liệu liên quan mà băm id đã biến mất. DEL
là nguyên tử và truy cập dữ liệu / ghi dữ liệu vào hàm băm là O (1).
Tôi nghĩ những gì có thể giúp bạn là MULTI / EXEC / DISCARD . Mặc dù không tương đương 100% với các giao dịch , bạn sẽ có thể tách biệt các xóa khỏi các bản cập nhật khác.
FYI.
redis-cli
keys
(sử dụng này scan
)Có lẽ bạn chỉ cần sửa đổi ký tự viết hoa.
quét-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
rõ ràng-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
Chạy tại bash prompt
$ ./clear-redis-key.sh key_head_pattern
Các câu trả lời khác có thể không hoạt động nếu khóa của bạn chứa ký tự đặc biệt - Guide$CLASSMETADATA][1]
ví dụ. Gói từng khóa vào dấu ngoặc kép sẽ đảm bảo chúng được xóa đúng cách:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs redis-cli del
Một phiên bản sử dụng SCAN thay vì KEYS (như được khuyến nghị cho các máy chủ sản xuất) và --pipe
thay vì xargs.
Tôi thích đường ống hơn xargs vì nó hiệu quả hơn và hoạt động khi các khóa của bạn chứa dấu ngoặc kép hoặc các ký tự đặc biệt khác mà trình bao của bạn thử và diễn giải. Sự thay thế regex trong ví dụ này bao bọc khóa trong dấu ngoặc kép và thoát khỏi bất kỳ dấu ngoặc kép nào bên trong.
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
Đây không phải là câu trả lời trực tiếp cho câu hỏi, nhưng vì tôi đã đến đây khi tìm kiếm câu trả lời của riêng mình, tôi sẽ chia sẻ điều này ở đây.
Nếu bạn có hàng chục hoặc hàng trăm triệu khóa bạn phải khớp, các câu trả lời được đưa ra ở đây sẽ khiến Redis không phản hồi trong khoảng thời gian đáng kể (phút?) Và có khả năng bị sập vì tiêu thụ bộ nhớ (chắc chắn, lưu nền sẽ đá vào giữa hoạt động của bạn).
Cách tiếp cận sau đây là xấu xí không thể phủ nhận, nhưng tôi đã không tìm thấy một cách tốt hơn. Nguyên tử là không thể nghi ngờ ở đây, trong trường hợp này, mục tiêu chính là giữ Redis và đáp ứng 100% thời gian. Nó sẽ hoạt động hoàn hảo nếu bạn có tất cả các khóa của mình trong một trong các cơ sở dữ liệu và bạn không cần phải khớp bất kỳ mẫu nào, nhưng không thể sử dụng http://redis.io/commands/FLUSHDB vì tính chất chặn của nó.
Ý tưởng rất đơn giản: viết một tập lệnh chạy trong một vòng lặp và sử dụng thao tác O (1) như http://redis.io/commands/SCAN hoặc http://redis.io/commands/RANDOMKEY để lấy khóa, kiểm tra nếu chúng phù hợp với mẫu (nếu bạn cần) và http://redis.io/commands/DEL chúng từng cái một.
Nếu có cách nào tốt hơn để làm điều đó, xin vui lòng cho tôi biết, tôi sẽ cập nhật câu trả lời.
Ví dụ triển khai với Randomkey trong Ruby, như một tác vụ cào, một sự thay thế không chặn của một cái gì đó như 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
Nó được thực hiện đơn giản thông qua chức năng "Xóa chi nhánh" trong FastoRedis , chỉ cần chọn chi nhánh mà bạn muốn xóa.
Vui lòng sử dụng lệnh này và thử:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
Tôi đã thử hầu hết các phương pháp được đề cập ở trên nhưng chúng không hiệu quả với tôi, sau một số tìm kiếm tôi đã tìm thấy những điểm sau:
-n [number]
del
nhưng nếu có hàng ngàn hoặc hàng triệu khóa thì tốt hơn nên sử dụng unlink
vì hủy liên kết là không chặn trong khi del đang chặn, để biết thêm thông tin, hãy truy cập trang này hủy liên kết với delkeys
giống như del và đang chặnVì vậy, tôi đã sử dụng mã này để xóa các khóa theo mẫu:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
Tôi hỗ trợ tất cả các câu trả lời liên quan đến việc có một số công cụ hoặc thực hiện biểu thức Lua.
Thêm một lựa chọn từ phía tôi:
Trong cơ sở dữ liệu sản xuất và tiền sản xuất của chúng tôi có hàng ngàn khóa. Thỉnh thoảng chúng ta cần xóa một số khóa (bằng một số mặt nạ), sửa đổi theo một số tiêu chí, v.v ... Tất nhiên, không có cách nào để thực hiện thủ công từ CLI, đặc biệt là có shending (512 dbs logic trong mỗi vật lý).
Với mục đích này, tôi viết công cụ máy khách java thực hiện tất cả công việc này. Trong trường hợp xóa khóa, tiện ích có thể rất đơn giản, chỉ có một lớp ở đó:
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();
}
}
Lệnh dưới đây làm việc cho tôi.
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
Spring RedisTemplate tự cung cấp các chức năng. RedissonClient trong phiên bản mới nhất đã không dùng chức năng "xóaByPotype".
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);
keys
và delete
các phương thức.