在开发过程中,经常会遇到Redis的机器内存过高而导致其他服务受到影响,主要原因是没有对一些临时的key设置过期时间或者定期清理,时间一长就会造成很多垃圾数据塞满内存,那么此时就可以通过keys命令将匹配到的key删除。

单节点Redis删除key

单节点不存在槽(slot)的概念,所以可以直接使用如下命令进行删除

1
redis-cli keys "*gitlab*"|xargs redis-cli del

上面的命令表示删除所有包含gitlab的key,使用keys *gitlab*将会得到如下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@ubuntu:~# redis-cli -n 0 keys "*gitlab*"  
1) "resque:gitlab:cron_job:expire_build_artifacts_worker"
2) "resque:gitlab:cron_job:admin_email_worker:enqueued"
3) "resque:gitlab:stat:failed:2019-07-07"
4) "resque:gitlab:stat:failed"
5) "resque:gitlab:cron_job:repository_check_worker"
6) "resque:gitlab:cron_jobs"
7) "resque:gitlab:stat:processed:2019-07-07"
8) "resque:gitlab:stat:failed:2019-07-07"
9) "resque:gitlab:cron_job:stuck_ci_builds_worker:enqueued"
10) "resque:gitlab:cron_job:repository_archive_cache_worker"
11) "resque:gitlab:cron_job:stuck_ci_builds_worker"
12) "resque:gitlab:processes"

那么这些key将会被删除。
当然,有些时候还会有分库的场景,单节点的Redis默认有16个数据库,那么还可以指定数据库来进行匹配删除,使用-n 数据库编号即可,例如,删除数据库2中的所有*gitlab*的key:

1
redis-cli -n 2 keys "*gitlab*"| xargs redis-cli -n 2 del

Redis Cluster模式删除key

如果Redis是集群的模式,那么此时数据库只能是0,并且不能使用keys命令和管道的组合来匹配删除了,因为数据分布在不同的节点的内存槽里面,需要针对每个节点的key进行删除,此时我们需要借助代码来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package xyz.cco.study;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.junit.Test;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
* @author Cco.Xyz
* @version 1.0
* date 2019-07-17 14:00
*/
public class TestRedisCluster {

@Test
public void testRedis() {
Set<HostAndPort> hostAndPortsSet = new HashSet<>();
// 添加节点 三主三从
hostAndPortsSet.add(new HostAndPort("10.10.170.161", 7000));
hostAndPortsSet.add(new HostAndPort("10.10.170.161", 7001));
hostAndPortsSet.add(new HostAndPort("10.10.170.161", 7002));
hostAndPortsSet.add(new HostAndPort("10.10.170.161", 7003));
hostAndPortsSet.add(new HostAndPort("10.10.170.161", 7004));
hostAndPortsSet.add(new HostAndPort("10.10.170.161", 7005));
// Jedis连接池配置
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(10);
jedisPoolConfig.setMaxTotal(30);
jedisPoolConfig.setMinIdle(0);
jedisPoolConfig.setMaxWaitMillis(200000); // 设置200秒
jedisPoolConfig.setTestOnBorrow(true);

JedisCluster jedisCluster = new JedisCluster(hostAndPortsSet, jedisPoolConfig);
Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
for (JedisPool pool : clusterNodes.values()) {
Jedis jedis = pool.getResource();
Set<String> keySet = jedis.keys("*gitlab*");
for (String key : keySet) {
System.out.println(key);
if (!key.equals("")) {
jedisCluster.del(key);
}

}
}
}
}

此时就会将每个节点保存的Key进行删除,不过速度比较慢,而且如果在redis的MaxWaitMillis没有删除完key,会出现保存。如果数据量较大,可以将MaxWaitMillis设置大一点,目前本程序中设置的200000毫秒,总共调用了3次,删除了20G的数据。代码中有个判断空的逻辑,我也不清楚为啥读出来有些key是"",所以就特殊处理了一下。