又是美好的一天呀~
个人博客地址: huanghong.top
本文预估阅读时长为10分钟左右~
RedisCluster路由
redis-cli客户端
- 根据key的有效部分使用CRC16函数计算出散列值,在对16383取余,得到slot编号。这样的key都会映射到0~16383槽范围内;
- 根据MOVED重定向机制,Redis客户端可以随机连接集群内任一redis节点(主从节点均可)获取其slot所在的node;
- 发送redis指令
- 如果指令在这个node上,则处理指令;
- 如果不在这个node上,则redis会返回给客户端MOVED重定向错误,通知客户端重新请求正确的node, 这个过程称为MOVED重定向。
使用redis-cli客户端普通连接redis主节点,来存取键值会返回MOVED重定向错误,键值并不能存取成功。
重定向信息中包含了slot和node的地址,根据重定向信息可以手动去请求正确的node。
使用redis-cli客户端集群模式连接(redis-cli -c)连接redis主节点,存取键值时redis-cli同样也会接收到MOVED重定向错误,但是会自动根据重定向信息来切换节点重新发起请求。
Smart客户端
基于Redission分析
-
根据配置文件获取RedisCluster集群节点信息
-
org.redisson.cluster.ClusterConnectionManager#scheduleClusterChangeCheck定时检测集群节点状态
-
org.redisson.cluster.ClusterConnectionManager#checkMasterNodesChange检测主节点状态
-
org.redisson.cluster.ClusterConnectionManager#addMasterEntry初始化slot和node的映射关系存储在
private final AtomicReferenceArray slot2entry = new AtomicReferenceArray<>(MAX_SLOT)中
-
redission客户端执行命令
//org.redisson.command.CommandAsyncService#writeAsync(java.lang.String, org.redisson.client.codec.Codec, org.redisson.client.protocol.RedisCommand<T>, java.lang.Object...) public <T, R> RFuture<R> writeAsync(String key, Codec codec, RedisCommand<T> command, Object... params) { RPromise<R> mainPromise = createPromise(); //解析key对应的slot NodeSource source = getNodeSource(key); async(false, source, codec, command, params, mainPromise, false, false); return mainPromise; } //org.redisson.cluster.ClusterConnectionManager#calcSlot(java.lang.String) public int calcSlot(String key) { if (key == null) { return 0; } int start = key.indexOf('{'); if (start != -1) { int end = key.indexOf('}'); if (end != -1 && start + 1 < end) { key = key.substring(start + 1, end); } } //使用CRC16算法计算出散列值,对16384取余 int result = CRC16.crc16(key.getBytes()) % MAX_SLOT; log.debug("slot {} for {}", result, key); return result; }
-
在ClusterConnectionManager中的slot2entry中, 根据key所对应的slot获取对应的节点信息
-
向节点发送请求命令
注:
- 期间redis客户端会以ping信号来关注集群节点信息,发现节点信息(节点状态、槽位信息等)改变后会变更本地缓存中的值;
- RedisCluster客户端接收到MOVED重定向后,会执行刷新缓存slot–>node映射表。
ASK重定向
当slot中的数据从源节点到目标节点迁移过程中,客户端需要保证key的命令可正常执行。
- 在进行重新分片期间,源节点向目标节点迁移一个槽的过程中,可能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里面,而另一部分键值对则保存在目标节点里面。
- 当客户端向源节点发送一个与数据库键有关的命令,并且命令要处理的数据库键恰好就属于正在被迁移的槽时。源节点会先在自己的数据库里面査找指定的键,如果找到的话,就直接执行客户端发送的命令。
- 否则,这个键有可能已经被迁移到了目标节点,源节点将向客户端返回一个 ASK 错误,指引客户端转向正在导入槽的目标节点,并再次发送之前想要执行的命令,从而获取到结果。
ASK与MOVED错误区别
- ASK错误发生在slot迁移过程中;
- MOVED错误发生在slot迁移完成或slot初始分配完成。
感谢阅读完本篇文章!!!
个人博客地址: huanghong.top