(error) ERR 'RENAME' command keys must in same slot
一、介绍
我们先来看基本的介绍
Redis Rename 命令用于修改 key 的名称 。
1、语法
redis rename命令的基本用法如下
RENAME OLD_KEY_NAME NEW_KEY_NAME
2、可用版本
= 1.0.0
3、返回值
将前面key的值替换为后面新的值
old_key_name 这个key必须存在,后面new_key_name这个key可以存在,也可以不存在,当存在时会覆盖之前的数据,因为key变了,前面key的数据也不存在了,当不存在时,直接替换旧key的名字
当改名成功会出现OK
当OLD_KEY_NAME 与 NEW_KEY_NAME 相同,或者 OLD_KEY_NAME 不存在时,返回错误,当 NEW_KEY_NAME 已经存在时,RENAME命令将覆盖旧值。
二、问题
一切都没问题,代码也这么写了,因为涉及多个key,所以使用了pipelining批量rename
redisTemplate.execute((RedisConnection connection) -> { Jedis jedis = (Jedis) connection.getNativeConnection(); Pipeline p = jedis.pipelined(); keys.forEach(key -> p.rename(key + TEMP_SUFFIX, key)); return p.sync(); });
然后上了测试,没问题。。
然后上了线上,定时任务执行,发现出了问题,因为使用了p.sync(),没有关心返回结果,也没有报错,也没有错误日志,但是新的key里面就是没有数据,最后一次一次复查代码,雀氏没问题呀,
最后在线上redis进行手动rename命令测试,发现了问题
rename rank1 rank
(error) ERR 'RENAME' command keys must in same slot
三、解决办法
究其原因,是因为测试环境是redis的单机模式,线上使用的是阿里云的Redis集群版,需要rename命令的两个key必须处于相同的插槽,为了使两个缓存key处于同一插槽
可以将两个key的公共部门使用{}
括起来,
- 如果想在集群模式使用rename命令,在设计key的时候,将公共部分用
{}
括起来,上述命令修改设计后执行为rename {rank}1 {rank}
- 或者避免这种用法,直接先删后查
四、原因
Redis Cluster在设计时没有使用一致性Hash (Consistency Hashing),而是使用数据分片引入哈希槽(Hash solt)来实现
一个Redis集群,默认有16384个hash槽(0-16383随机分配)向redis集群添加数据的时候,经过Redis的hash运算,
集群使用公式slot=CRC16(key)/16384来计算key属于哪个槽,其中CRC16(key)语句用于计算key的CRC16 校验和。
判断这个key应该存放的槽位是在哪个,在看这个槽位属于哪个节点,然后这个key就添加到这个节点上