在我的 Redis DB 中,我有许多prefix:<numeric_id>
哈希值。
有时我想以原子方式清除它们。如何在不使用某些分布式锁定机制的情况下做到这一点?
在 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),因此您的应用程序会将新数据写入键 prefix:3:1 和 prefix:3:2。然后,您可以安全地从 prefix:2:1 和 prefix: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 开始,您真的想使用SCAN命令而不是 KEYS[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] KEYS是一个危险的命令,可能会导致 DoS。以下是其文档页面的引用:
警告:将 KEYS 视为仅应极其小心地在生产环境中使用的命令。当它针对大型数据库执行时,它可能会破坏性能。此命令用于调试和特殊操作,例如更改键空间布局。不要在常规应用程序代码中使用 KEYS。如果您正在寻找一种在键空间子集中查找键的方法,请考虑使用集合。
更新:一个具有相同基本效果的衬里 -
$ 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
,您就可以开始了。
信用 lisco 来自:http ://redis.io/commands/del
我在 redis 3.2.8 中使用以下命令
redis-cli KEYS *YOUR_KEY_PREFIX* | xargs redis-cli DEL
您可以从此处获得与键模式搜索相关的更多帮助:- https://redis.io/commands/keys。根据您的要求使用您方便的 glob 样式模式,例如*YOUR_KEY_PREFIX*
orYOUR_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);
}
}
谢谢 :)
您还可以使用此命令删除密钥:-
假设您的 redis 中有多种类型的键,例如-
Ex- ' 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中的所有内容,请按照以下命令进行操作-
使用 redis-cli:
例如:- 在您的外壳中:
redis-cli flushall
redis-cli flushdb
@mcdizle 的解决方案不起作用,它仅适用于一个条目。
这个适用于所有具有相同前缀的键
EVAL "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" 0 prefix*
注意:您应该将“前缀”替换为您的密钥前缀...
如果键名中有空格,则可以在 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
这也使用了 SCAN,它在生产中比 KEYS 更可取,但不是原子的。
如果您的密钥包含特殊字符,其他答案可能不起作用 -Guide$CLASSMETADATA][1]
例如。将每个键包装成引号将确保它们被正确删除:
redis-cli --scan --pattern sf_* | awk '{print $1}' | sed "s/^/'/;s/$/'/" | xargs 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没有这样的功能。
我所做的:将会话数据存储在hash中。我只是创建一个哈希 id 的哈希session:sessionid
,然后在该哈希中推送key-x
, key-y
, key-z
(顺序对我来说无关紧要),如果我不再需要该哈希,我只需执行 aDEL session:sessionid
并且与该哈希 id 关联的所有数据都消失了。DEL
是原子的,访问数据/将数据写入哈希是 O(1)。
// TODO
您认为它的命令没有意义,但有时 Redis 命令就像DEL
无法正常工作一样,可以解决这个问题
redis-cli KEYS "*" | xargs -i redis-cli EXPIRE {} 1
这是生活黑客
使用 SCAN 而不是 KEYS(推荐用于生产服务器)--pipe
而不是 xargs 的版本。
我更喜欢管道而不是 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
我认为可能对您有所帮助的是MULTI/EXEC/DISCARD。虽然不是100% 等同于 transactions,但您应该能够将删除与其他更新隔离开来。
供参考。
redis-cli
keys
(这使用scan
)也许您只需要修改大写字符。
扫描匹配.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
清除-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
请使用此命令并尝试:
redis-cli --raw keys "$PATTERN" | xargs redis-cli del
这不是问题的直接答案,但由于我是在寻找自己的答案时来到这里的,所以我会在这里分享。
如果您必须匹配数千万或数亿个键,则此处给出的答案将导致 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一一匹配。
如果有更好的方法,请告诉我,我会更新答案。
在 Ruby 中使用 randomkey 的示例实现,作为 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
我尝试了上面提到的大多数方法,但它们对我不起作用,经过一些搜索后我发现了以下几点:
-n [number]
del
,但如果有数千或数百万个键,则最好使用unlink
,因为unlink 是非阻塞的,而 del 是阻塞的,有关更多信息,请访问此页面unlink vs delkeys
像 del 并且正在阻塞所以我用这段代码按模式删除键:
redis-cli -n 2 --scan --pattern '[your pattern]' | xargs redis-cli -n 2 unlink
添加到这个答案:
要查找前 1000 个键:
EVAL "return redis.call('scan', 0, 'COUNT', 1000, 'MATCH', ARGV[1])" 0 find_me_*
要删除它们:
EVAL "return redis.call('del', unpack(redis.call('SCAN', 0, 'COUNT', 1000, 'MATCH', ARGV[1])[2]))" 0 delete_me_*
我用最简单的 EVAL 命令变体成功了:
EVAL "return redis.call('del', unpack(redis.call('keys', my_pattern_here*)))" 0
我my_pattern_here
用我的价值代替。
下面的命令对我有用。
redis-cli -h redis_host_url KEYS "*abcd*" | xargs redis-cli -h redis_host_url DEL
这个对我有用,但可能不是原子的:
redis-cli keys "stats.*" | cut -d ' ' -f2 | xargs -d '\n' redis-cli DEL
穷人的原子质量删除?
也许您可以将它们全部设置为 EXPIREAT 同一秒 - 比如未来几分钟 - 然后等到那个时候,同时看到它们全部“自毁”。
但我不确定那将是多么原子。
现在,您可以使用 redis 客户端并首先执行 SCAN(支持模式匹配),然后单独 DEL 每个键。
但是,redis 官方 github 上有一个问题,在这里创建一个模式匹配-德尔,如果你觉得它有用,就给它一些爱吧!
如果您的键名中有空格,这将适用于 MacOS
redis-cli --scan --pattern "myprefix:*" | tr \\n \\0 | xargs -0 redis-cli unlink
我支持所有与拥有一些工具或执行 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();
}
}
如果您使用的是低于 4 的 Redis 版本,您可以尝试
redis-cli -h 127.0.0.1 -p 26379 -a `yourPassword` --scan --pattern data:* | xargs redis-cli del
如果您使用的是上述 4 个版本,那么
redis-cli -h 127.0.0.1 -p 26379 -a `yourPassword` --scan --pattern data:*| xargs redis-cli unlink
要检查您的版本,请使用以下命令输入您的 Redis 终端
redis-cli -h 127.0.0.1 -p 26379 -a `yourPassword
然后输入
> INFO
# Server
redis_version:5.0.5
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:da75abdfe06a50f8
redis_mode:standalone
os:Linux 5.3.0-51-generic x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:7.5.0
process_id:14126
run_id:adfaeec5683d7381a2a175a2111f6159b6342830
tcp_port:6379
uptime_in_seconds:16860
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:15766886
executable:/tmp/redis-5.0.5/src/redis-server
config_file:
# Clients
connected_clients:22
....More Verbose
如果您使用 windows 环境,请按照以下步骤操作,它肯定会起作用:
从这里下载 GOW - https://github.com/bmatzelle/gow/wiki(因为 xargs 命令在 Windows 中不起作用)
下载适用于 Windows 的 redis-cli(详细说明在这里 - https://medium.com/@binary10111010/redis-cli-installation-on-windows-684fb6b6ac6b)
运行cmd打开redis-cli存储的目录(例如:D:\Redis\Redis-x64-3.2.100)
如果您想删除以“Global:ProviderInfo”开头的所有键,请执行此查询(需要更改粗体参数(主机、端口、密码、键)并编写您的,因为这只是示例):
redis-cli -h redis.test.com -p 6379 -a redispassword --raw keys " Global:ProviderInfo *" | xargs redis-cli -h redis.test.com -p 6379 -a redispassword del
这是不使用任何 xargs 魔法的最简单方法
纯粹的狂欢!
redis-cli DEL $(redis-cli KEYS *pattern*)
Spring RedisTemplate 本身提供了该功能。最新版本中的 RedissonClient 已弃用“deleteByPattern”功能。
Set<String> keys = redisTemplate.keys("geotag|*");
redisTemplate.delete(keys);