2
votes

As I understand in redis cluster the slots are distributed, the DEL command which can take multiple keys fails with a CROSSSLOT Keys in request don't hash to the same slot error.

Since my existing codebase is designed around batch processing, there are quite a few places where the redis cache delete operation is called with a list of keys to be deleted. As changing this would not be a smart idea I am trying to find a solution at my cache interface layer where I can still receive the multiple keys to be deleted and add required logic here to achieve the same final result. I had two options in my view which I need help with

Method 1. Loop on the keys and use Go routines + weight groups

Method 2. Use EVAL : I am not sure if this is the right direction or if I am using it right. Following is the sample golang snippet below

func (c CacheClient) Del(ctx context.Context, keysToBeDeleted []string) error {
    // _, err := c.client.Del(strings.Join(keysToBeDeleted, " ")).Result() // previously used when on single redis instance
    _, err := c.client.Eval("return redis.call('DEL', KEYS[1])", keysToBeDeleted).Result()

    if err != nil {
        // handle error
    }
    return nil
}

I created a dummy cluster and used redis-cli to test the eval command as below

redis> EVAL "redis.call('del', KEYS[1]) " 2 mykey1, mykey2

This too failed with a CROSSSLOT Keys in request don't hash to the same slot error.

Am I using the KEYS table in a wrong way in the Lua script. Or what is the right way to delete multiple keys from a cluster. Should I stick to method 1?

Using Golang v1.13 and redis.v5 as my redis-client package. If someone can help me find a solution using the redis.v5 package itself that would be even great.

1
Does this answer your question? Redis Cross Slot error - Shudipta Sharma
Yes partially. Helps me understand that Lua wouldn’t be helpful here. But I still would like to understand possible options here. Preferably something other than hash tags or restricting keys to hash slots - rajat
@rajat you might want to consider using RedisGears, which allow you to run cross slots/shards operations - Guy Korland

1 Answers

2
votes

I'm not sure using a Lua script will help you with that. Lua scripts are good for forcing atomicity, but won't help you overcome the issue with multiple slots.

Two possible solutions for your issue are:

  1. Use Redis hash tags. What it means is that if you have a common substring in all your keys (e.g. ["mykey_a", "mykey_b", ...]), then you can force Redis to group all the keys to the same slot by adding curly braces around the common substring (["{mykey}_a", "{mykey}_b", ...]). Obviously it is not recommended to use the same slot for all of your keys, but if you can group some of them for a certain purpose, then this solution is valid.

  2. Use Redis pipelines. This way, you perform each DEL command separately, but save the network RTT. Pipeline in Go can look like:

pipe := c.client.Pipeline()
for _, key := range keys {
    pipe.Del(key)
}
pipe.Exec()