Delete keys matching a specific pattern in Redis

Posted by ChenRiang on March 13, 2022

Deleting key(s) in Redis is pretty straightforward, you only need to issue a DEL command. However, DEL command can only remove the key(s) that exact match stated in the command, it does not support deleting key(s) that matched a pattern. In this blog post, we are going to look into how to delete multiple keys matching a specific pattern in Redis and execute them using Java Springboot.

Delete via Lua script

The idea to achieve the objective is very simple, search and delete. We will create a Lua script to search for key that matched the given pattern and delete the response return.

1
2
3
4
5
6
7
8
9
10
11
local cursor="0";

repeat
 local scanResult = redis.call("SCAN", cursor, "MATCH", "<Search key pattern>");
    local keys = scanResult[2];
    for i = 1, #keys do
        local key = keys[i];
        redis.call("DEL", key);
    end;
    cursor = scanResult[1];
until cursor == "0";

We used SCAN command instead of KEYS which return the similar result. The difference of these two commands is that, KEYS will scan all the keys in Redis with the provided matching pattern in a single go; SCAN will return a small number of search results and a cursor which indicate the current search position. With SCAN we can do scan incrementally without blocking the server traffic. We will loop the result with DEL command until there is no more further result (cursor = "0")

Execute in single node

We will run the Lua script with Java Spring Data. See Spring Data Redis to understand the setup.

cleanup.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local pattern= ARGV[1];

local cursor="0";

repeat
    local scanResult = redis.call("SCAN", cursor, "MATCH", pattern);
    local keys = scanResult[2];
    for i = 1, #keys do
        local key = keys[i];
        redis.call("DEL", key);
    end;
    cursor = scanResult[1];
until cursor == "0";

return "";

Java

1
2
3
4
5
6
7
8
9
10
 public class RedisService {
     @Autowired
     private RedisTemplate<String, String> redisTemplate;

     public void cleanup(String pattern) {
        Resource scriptSource = new ClassPathResource("cleanup.lua");
        RedisScript<String> redisScript = RedisScript.of(scriptSource, String.class);
        redisTemplate.execute(redisScript, Collections.emptyList(), pattern);
    }
 }

Execute in cluster

You might notice some of the keys is not clear up when running above script on a Redis cluster. This is because redisTemplate will only send the script to randomly to only 1 node if we did not provide any key. A Redis cluster is divided up among 16,384 slots and these hash slots are a logical division of the keys.

e.g. In a 4 node cluster, the layout of slot will be :

Slot Node
0 - 4095 0
4096 - 8191 1
8192 - 12287 2
12288 - 16384 3

To force the script to be run in every node, we need to get all the keys that belong to each corresponding node.

cleanup.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local pattern= ARGV[1];

local cursor="0";

repeat
    local scanResult = redis.call("SCAN", cursor, "MATCH", pattern);
    local keys = scanResult[2];
    for i = 1, #keys do
        local key = keys[i];
        redis.call("DEL", key);
    end;
    cursor = scanResult[1];
until cursor == "0";

return "";

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 public class RedisService {
     @Autowired
     private RedisTemplate<String, String> redisTemplate;

     public void cleanup(String pattern) {
        Resource scriptSource = new ClassPathResource("cleanup.lua");
        RedisScript<String> redisScript = RedisScript.of(scriptSource, String.class);
         
        RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
        for (RedisClusterNode clusterNode : connectionFactory.getClusterConnection().clusterGetNodes()) {
            String key = redisTemplate.opsForCluster().randomKey(clusterNode);
            redisTemplate.execute(redisScript, Collections.singletonList(key), pattern);
        }
    }
 }

Conclusion

In this post, we have looked into how to delete Redis key according to a given pattern and how to execute them using Java.

Reference

Ways to delete multiple keys from Redis cache - link