一. ASK 错误
集群上篇最后讲到, 对于重新分片由 Redis-trib 负责执行, 关于该工具以后再介绍. 在进行重新分片期间, 源节点向目标节点迁移一个槽的过程中, 可以会出现该槽中的一部分键值对保存在源节点中, 另一部份键值对则保存在目标节点中.
当客户端向源节点发送一个与数据库键有关的命令时, 并且命令要处理的数据库键正好就是正在被迁移的槽时, 会出现二种情况的一种:
(1) 源节点会先在自己的数据库中查找指定的键, 如果找到的话, 就会直接执行客户端发送的命令.
(2) 相反, 如果在源节点找不到指定的键, 那么键有可能已经被迁移到了目标节点, 源节点将向客户端返回一个 ASK 错误, 指引客户端转向正在导入槽的目标节点, 并再次发送之前想要执行的命令.
注意: 和接到 Moved 错误时的情况一样, 集群模式的 Redis-cli 在接到 ask 错误时也不会打印错误, 而是自动根据错误提供的 ip 和 port 进行转向 (Redirected to ..) 动作.
1.1 cluster setslot importing 命令实现
在 clusterState 结构的 importing_slots_from 数组中, 记录了当前节点正在从其他节点导入的槽号. 在集群进行重新分片的时候, 向目标节点发送以下命令, 格式为:
cluster setslot <slot> importing <node ID>
slot 和 node_id 是指: 源节点槽号和源节点 ID. 比如在上一篇结尾, 原属于 7002 节点的 14042 号槽, 迁移到了目标 7003 节点, 在 7003 节点中内部 clusterState 结构的 importing_slots_from 数组下记录了 14042 号槽, 并且还记录了源节点 ip 和端口(127.0.0.1 7002).
1.2 cluster setslot migrating 命令实现
在 clusterState 结构的 migrating_slots_to 数组中, 记录了当前节点正在迁移至其他节点的槽. 在集群进行重新分片的时候, 向源节点发送命令以下命令, 格式为:
cluster setslot <slot> migrating <node ID>
slot 和 node_id 是指: 目标节点槽号和目标节点 ID.
下图左边 7003 目标节点 importing_slots_from 数组 和 右边 7002 源节点的 migrating_slots_to 数组:
1.3 ASK 错误后的引导
如果节点收到一个关于键 key 的命令请求, 并且键 key 所属的槽 i 正好就指派给了这个节点, 如果节点没有在自己的数据库里找到键 key, 那么节点会检查自己的迁移数组 clusterState.migrating_slots_to[i], 看键 key 所属的槽 i 是否正在进行迁移, 如果槽 i 的确在进行迁移, 那么节点会向客户端发送一个 ask 错误, 引导客户端到正在导入槽 i 的节点去查找键 key.
1.4 ASK 错误和 Moved 错误的区别
ASK 错误和 Moved 错误都会导致客户端转向, 它们区别在于:
(1) Moved 错误代表槽的负责权, 已经从一个节点转移到了另一个节点: 在客户端收到关于槽 i 的 mvoed 错误之后, 客户端每次遇到关于槽 i 的命令请求时, 都可以直接将命令请求发送到 moved 错误所指向的节点, 因为该节点就是目前负责槽 i 的节点.
(2) 与此相反, ASK 错误只是两个节点在迁移槽的过程中使用的一种临时措施: 在客户端收到关于槽 i 的 ASK 错误之后, 客户端只会在接下来的一次命令请求中将关于槽 i 的命令请求发送到 ASK 错误所指示的节点.
二. 复制与故障转移
集群中的节点分为主节点和从节点, 主节点用于处理槽, 而从节点则用于复制某个主节点, 当主节点下线时, 从节点代替主节点继续处理命令请求.
复制设置从节点: 在主节点将设置 node_id (node_id 为从节点), 脚本如下:
CLUSTER REPLICATE <node_id>
2.1 节点故障检测
集群中的每个节点都会定期向群集中的其他节点发送 ping 消息, 以此来检测对方是否在线, 如果接收 ping 消息的节点没有在规定的时间内返回 pong 消息, 那么发送节点就会将接收节点标记为疑似下线 pfail(probable fail).
集群中的各个节点会通过互相发送消息的方式来交换集群中各个节点的状态信息, 来判断节点是处于在线, 疑似下线还是下线(fail) 状态.
在集群中, 负责处理槽的节点在半数以上都将某个主节点 x 报告为疑似下线状态时, 那么这个主节点 x 将标记为已下线 fail. 将主节点 x 标记为已下线的节点会向集群广播一条关于主节点 x 的 fail 消息.
2.2 故障转移实现步骤
当一个从节点发现自己正在复制的主节点进入已下线状态时, 从节点将开始对下线主节点进行故障转移, 步骤如下:
(1) 复制下线主节点的所有从节点, 会有一个从节点被选中.
(2) 被选中的从节点会执行 slaveof no one 命令, 成为新的主节点.
(3) 新的主节点会撤消所有对已下线主节点的槽指派, 并将这些槽指派给自己.
(4) 新的主节点向集群广播一条 pong 消息, 这条 pong 消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点, 并且接管了原本已下线的节点负责处理的槽.
(5) 新的主节点开始接收和自己负责处理的槽有关的命令请求, 故障转移完成.
2.3 节点之间的通信
集群中的各个节点通过发送和接收消息来进行通信, 节点发送的消息主要以 5 种:
(1) meet 消息: 发送者向接收者发送 meet 消息, 请求接收者加入到发送者当前所处的集群中.
(2) ping 消息: 集群中每个节点默认每隔 1 秒就会从已知节点列表随机选出 5 个节点, 然后对这 5 个节点中最长时间没有发送过 ping 消息的节点发送 ping 消息, 以此来检测被选中的节点是否在线.
(3) pong 消息: 当接收者收到 meet 或 ping 消息时, 会向发送者返回一条 pong 消息, 以此表明自己 (接收者) 节点是正常的. 另外一个节点也可以通过向集群广播自己的 pong 消息来让集群中的其他节点刷新关于这个节点的认识.
(4) Fail 消息: 当一个主节点 A 判断另一个主节点 B 已经进入 Fall 状态时, 节点 A 会向集群广播一条关于节点 B 的 Fall 消息, 所有收到这条消息的节点都会立即将节点 B 标记为已下线.
(5) publish 消息: 当节点接收到一个 publish 命令时, 节点会执行这个命令, 并向集群广播一条 publish 消息, 所有接收到这条 publish 消息的节点都会执行相同的 publish 命令.
三. 集群知识点总结
(1) 节点通过握手来将其他节点添加到自己所处的集群当中.
(2) 集群中的 16384 个槽可以分别指派给集群中的各个节点, 通过 cluster nodes 命令可以看到节点的槽分布.
(3) 节点在接到一个命令请求时, 先检查这个命令请求要处理的键所在的槽是否由自己负责, 如果不是, 节点向客户端返回一个 moved 错误, moved 错误携带的信息可以指引客户端转向至正在负责相关槽的节点继续来处理.
(4)对 Redis 集群的重新分片工作是由 Redis-trib 负责执行的, 重新分片是将属于某个槽的所有键值对从一个节点转移至另一个节点.
(5)如果节点 A 正在迁移槽 i 到节点 B, 当节点 A 没能在自己的数据库中找到命令指定的键时, 节点 A 向客户端返回一个 ASK 错误, 指引客户端到节点 B 继续查找指定键.
(6) Moved 错误代表槽的负责权已经从一个节点转移到了另一个节点, 而 ASK 错误只是两个节点在迁移槽的过程中使用的一种临时措施.
(7) 集群中的从节点用于复制主节点, 并在主节点下线时, 代替主节点继续处理命令请求.
(8) 集群中的节点通过发送和接收消息来进行通信, 常见的消息包括 meet;ping ;pong;publish;fail 五种.
来源: https://www.cnblogs.com/MrHSR/p/10184619.html