文章 39
评论 3
浏览 384120
【Redis】解决批操作Keys,key在不同(slot)槽的问题

【Redis】解决批操作Keys,key在不同(slot)槽的问题

在我们使用redis批操作时,如mget、以及lua脚本中操作KEYS,会遇到如下错误,

No way to dispatch this command to Redis Cluster because keys have different slots.

这个错误是因为, Redis cluster对多key操作有限,要求命令中所有的key都属于一个slot,才可以被执行。

然后查看jedis源码

public T run(int keyCount, String... keys) {
	if (keys != null && keys.length != 0) {
		if (keys.length > 1) {
			int slot = JedisClusterCRC16.getSlot(keys[0])

			for(int i = 1; i < keyCount; ++i) {
				int nextSlot = JedisClusterCRC16.getSlot(keys[i]);
				if (slot != nextSlot) {
					throw new JedisClusterException("No way to dispatch this command to Redis Cluster because keys have different slots.");
				}
			}
		}
		return this.runWithRetries(SafeEncoder.encode(keys[0]), this.redirections, false, false);
	} else {
		throw new JedisClusterException("No way to dispatch this command to Redis Cluster.");
	}
}

jedis 会将KEYS 的第一个key的slot作为基准,循环依次比较剩余key的slot是否一致,如果不一致就会报刚才的错误,继续看源码,getSlot(String) 方法的实现:

public static int getSlot(String key) {
	int s = key.indexOf("{");
		if (s > -1) {
			int e = key.indexOf("}", s + 1);
			if (e > -1 && e != s + 1) {
				key = key.substring(s + 1, e);
			}
		}

	return getCRC16(key) & 16383;
}

可以看出,这个方法,先是判断key是否包含大括号,{},如果有,取大括号中间的内容,作为计算slot;没有,则使用完整的key作为slot计算。到此,问题就得到了解决,我们将批量操作的keys,都用大括号包裹相同的字符串,就可以使,这批keys计算出的slot一致,如下:

{slot:mark}:key1
{slot:mark}:key2
{slot:mark}:key3

到此问题完美解决。


标题:【Redis】解决批操作Keys,key在不同(slot)槽的问题
作者:T-Aoker
地址:https://aoaos.top/articles/2021/08/05/1628131989109.html

修仙猿之旅

取消