17.3 在集群中执行命令
16384个槽全部进行了指派之后,集群进入上线状态,此时客户端就可以向集群中的节点发送数据命令了
当客户端向节点发送与数据库键有关的命令时:
17.3.1 计算键属于哪个槽
计算给定键key属于哪个槽的算法:
CLUSTER KEYSLOT 可以查看给定键属于哪个槽,其实现为:
17.3.2 判断槽是否由当前节点负责处理
clusterState.slots中的项与clusterState.myself进行比较:
17.3.3 MOVED错误
格式为:MOVED < slot > < ip >:< port >
slot为key所在槽,ip和port是负责处理槽的节点的ip和端口号
客户端根据ip和端口转向至此节点的socket,重新发送命令
注意:集群模式的moved错误不会打印,因为集群可以进行处理;而单机模式则会,因为单机模式的客户端并不清楚moved错误的作用,不会自动转向,只会打印
17.3.4 节点数据库的实现
集群节点与单机服务器在数据库方面保存键值对以及键值对过期时间的方式相同
集群节点与单机服务器在数据库方面的区别一是:节点只能使用0号数据库,单机服务器则没有此限制
例子:列表键list(带有过期时间)、哈希键book(带有过期时间)、字符串键date
节点使用clusterState的slots_to_keys跳跃表来保存槽和键之间的关系:
[外链图片转存失败(img-MovrEAMT-1563274534269)(…/markdownPicture/assets/1563157228366.png)]
例子:数据同上:列表键list(带有过期时间)、哈希键book(带有过期时间)、字符串键date
17.4 重新分片
作用:更改节点
可以在线进行,集群不需要下线,源和目标节点都可以继续处理命令请求
- 实现原理
由Redis集群管理软件redis-trib负责执行,通过向源节点和目标节点发送Redis提供的进行重新分片的命令来进行重新分片操作
redis-trib对集群的单个槽slot进行重新分片的步骤:
目标节点做好准备、源节点做好准备、获取源节点键值对、迁移到目标节点、重复执行3、4直到所有键值对迁移完毕、通知整个集群节点槽迁移的信息:
迁移键的过程:第3、4步
17.5 ASK错误
重新分片时,键值对可能还在源节点,可能到了目标节点
当客户端向源节点发送一个与数据库键有关的命令,且该命令要处理的键恰好就属于正在被迁移的槽时,运行流程如下:
注意:集群模式的ask错误不会打印,因为集群可以进行处理;而单机模式则会,因为单机模式的客户端并不清楚ask错误的作用,不会自动转向,只会打印;类似moved错误的处理过程
接下来讲解ASK实现原理,对比ask和moved的区别
17.5.1 CLUSTER SETSLOT IMPORTING命令的实现
”重新分片的步骤“的第一步命令:CLUSTER SETSLOT IMPORTING <source_id>,将当前节点(目标节点)clusterState.import_slots_from[i]的值设置为source_id所代表节点的clusterNode结构
clusterState结构的importing_slots_from数组记录了当前节点正在从其他节点导入的槽:
某个索引值i指向一个clusterNode结构,则代表当前节点正在从clusterNode所代表的节点导入槽i
例子:客户端向7003发送CLUSTER SETSLOT 16198 IMPORTING 9dfb4w1sd15w11ds…(7002的id),则7003为:
17.5.2 CLUSTER SETSLOT MIGRATING命令的实现
”重新分片的步骤“的第二步命令:CLUSTER SETSLOT IMPORTING <target_id>,将源节点clusterState.migrating_slots_to[i]的值设置为target_id所代表节点的clusterNode结构
clusterState的migrating_slots_to数组记录了当前节点正在迁移至其他节点的槽:
某个索引值i指向一个clusterNode结构,则代表当前节点正在将槽迁移至clusterNode所代表的节点
例子:客户端向节点7002发送CLUSTER SETSLOT 16198 MIGRAING 16516516ASD(7003的id),则7002为:
17.5.3 ASK错误的执行
如果节点收到一个关于键key的命令请求,且键key所属的槽i正好就指派给了这个节点:
1.如果节点在自己的数据库里找到键key,则执行客户端发送的命令
2.如果没有找到,则检查clusterState.migrating_slots_to[i],看键所属的槽i是否正在进行迁移,若是,则节点向客户端发送一个ASK错误,引导客户端到正在导入槽i的节点去查找键key
收到ASK错误的客户端执行的操作:
例子:客户端发送GET "love"给7002,此键在槽16198上,此槽正在迁移至7003
17.5.4 ASKING命令
任务:打开发送该命令的客户端的REDIS_ASKING标识,可以客户端手动发送;此标识是一次性的
作用:用于判断当前节点是否要执行客户端命令的流程中
例子:
假设7003正在导入7002的槽16198,则客户端向7003发送键命令,节点会返回moved错误,指引客户端转向7002;
如果客户端是先发送ASKING命令再发送键命令,则键命令会被7003执行;
此次执行过后,ASKING命令就失效了,若还是要发送键命令,则需要先发送ASKING
17.5.5 ASK和MOVED的区别
简易版: