一、分片路由:分片路由:
### --- 分片
~~~ 不同节点分组服务于相互无交集的分片(sharding),
~~~ Redis Cluster 不存在单独的proxy或配置服务器,所以需要将客户端路由到目标的分片。
二、客户端路由
### --- 客户端路由
~~~ Redis Cluster的客户端相比单机Redis 需要具备路由语义的识别能力,且具备一定的路由缓存能力。
### --- moved重定向
~~~ 每个节点通过通信都会共享Redis Cluster中槽和集群中对应节点的关系
~~~ 客户端向Redis Cluster的任意节点发送命令,接收命令的节点会根据CRC16规则进行hash运算与16384取余,计算自己的槽和对应节点
~~~ 如果保存数据的槽被分配给当前节点,则去槽中执行命令,并把命令执行结果返回给客户端
~~~ 如果保存数据的槽不在当前节点的管理范围内,则向客户端返回moved重定向异常
~~~ 客户端接收到节点返回的结果,如果是moved异常,则从moved异常中获取目标节点的信息
~~~ 客户端向目标节点发送命令,获取命令执行结果
[root@linux123 ~]# cd /opt/yanqi/servers/redis-cluster/7001/bin
[root@linux123 bin]# ./redis-cli -h 127.0.0.1 -p 7001 -c
127.0.0.1:7001> set name:001 zhaoyun
OK
127.0.0.1:7001> get name:001
"zhaoyun"
[root@linux123 bin]# ./redis-cli -h 127.0.0.1 -p 7002 -c
127.0.0.1:7002> get name:001
-> Redirected to slot [4354] located at 192.168.1.123:7001
"zhaoyun"
192.168.1.123:7001> cluster keyslot name:001
(integer) 4354
### --- ask重定向
~~~ 在对集群进行扩容和缩容时,需要对槽及槽中数据进行迁移
~~~ 当客户端向某个节点发送命令,节点向客户端返回moved异常,告诉客户端数据对应的槽的节点信息
~~~ 如果此时正在进行集群扩展或者缩空操作,当客户端向正确的节点发送命令时,
~~~ 槽及槽中数据已经被迁移到别的节点了,就会返回ask,这就是ask重定向机制
~~~ 客户端向目标节点发送命令,目标节点中的槽已经迁移支别的节点上了,此时目标节点会返回ask转向给客户端
~~~ 客户端向新的节点发送Asking命令给新的节点,然后再次向新节点发送命令
~~~ 新节点执行命令,把命令执行结果返回给客户端
~~~ moved和ask的区别
~~~ moved:槽已确认转移
~~~ ask:槽还在转移过程中
### --- Smart智能客户端
~~~ # JedisCluster
~~~ JedisCluster是Jedis根据RedisCluster的特性提供的集群智能客户端
~~~ JedisCluster为每个节点创建连接池,并跟节点建立映射关系缓存(Cluster slots)
~~~ JedisCluster将每个主节点负责的槽位一一与主节点连接池建立映射缓存
~~~ JedisCluster启动时,已经知道key,slot和node之间的关系,可以找到目标节点
~~~ JedisCluster对目标节点发送命令,目标节点直接响应给JedisCluster
~~~ 如果JedisCluster与目标节点连接出错,则JedisCluster会知道连接的节点是一个错误的节点此时节点返回moved异常给JedisCluster
~~~ JedisCluster会重新初始化slot与node节点的缓存关系,然后向新的目标节点发送命令,目标命令执行命令并向JedisCluster响应
三、如果命令发送次数超过5次,则抛出异常"Too many cluster redirection!"
JedisPoolConfig config = new JedisPoolConfig();
Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
jedisClusterNode.add(new HostAndPort("192.168.127.128", 7001));
jedisClusterNode.add(new HostAndPort("192.168.127.128", 7002));
jedisClusterNode.add(new HostAndPort("192.168.127.128", 7003));
jedisClusterNode.add(new HostAndPort("192.168.127.128", 7004));
jedisClusterNode.add(new HostAndPort("192.168.127.128", 7005));
jedisClusterNode.add(new HostAndPort("192.168.127.128", 7006));
JedisCluster jcd = new JedisCluster(jedisClusterNode, config);
jcd.set("name:001","zhangfei");
String value = jcd.get("name:001");
四、迁移
### --- 迁移
~~~ 在RedisCluster中每个slot 对应的节点在初始化后就是确定的。
~~~ 在某些情况下,节点和分片需要变更:
~~~ 新的节点作为master加入;
~~~ 某个节点分组需要下线;
~~~ 负载不均衡需要调整slot 分布。
~~~ 此时需要进行分片的迁移,迁移的触发和过程控制由外部系统完成。包含下面 2 种:
~~~ 节点迁移状态设置:迁移前标记源/目标节点。
~~~ key迁移的原子化命令:迁移的具体步骤。
~~~ 向节点B发送状态变更命令,将B的对应slot 状态置为importing。
~~~ 向节点A发送状态变更命令,将A对应的slot 状态置为migrating。
~~~ 向A 发送migrate 命令,告知A 将要迁移的slot对应的key 迁移到B。
~~~ 当所有key 迁移完成后,cluster setslot 重新设置槽位。