深入Redis原理与应用——Redis中的集群

概念

(1)一个 redis 集群通常由多个节点组成,刚开始的时候每个节点都是独立的,为了组件一个可工作的集群,必须将各个独立的节点连接起来,构成一个包含多节点的集群。
(2)一个节点 node 发送 CLUSTER MEET 命令。可以让 node 节点与 ip 和 port 所指定的节点进行握手,握手成功后 node 就会将指定 ip 和 host 的节点加入集群中。

启动节点

(1)一个节点就是一个运行在集群模式下的 redis 服务器,redis 服务器在启动时会根据cluster-enabled 配置选项是否为 yes 来决定是否开启服务器集群模式。
(2)节点会继续使用所有在单机模式中使用的服务器组件,比如使用文件事件处理器处理命令请求、使用时间事件处理器执行 serverCron 函数,serverCron 函数又会调用集群模式特有的 clusterCron 函数,其负责执行集群模式下的常规操作;持久化功能、复制功能等。
(3)集群的数据结构:clusterNode 结构保存了当前节点的状态,其中的 link 属性保存了一个 clusterLink 结构,保存了连接节点的有关信息,包括套接字接口和输入输出缓冲区;还有一个 clusterState 结构保存了当前节点的视角下集群所处的状态。

CLUSTER MEET 命令的实现

(1)客户端通过发送 CLUESTER MEET 命令和节点 B 的信息给节点 A,收到命令的节点 A 将与节点 B 进行握手,并依次来确认彼此的存在。
(2)节点 A 会为节点 B 创建一个 clusterNode 结构,并将该结构添加到自己的clusterState.nodes 字典里面。
(3)之后,节点 A 会根据 CLUSTER MEET 命令给定的 IP 地址和端口号向节点 B 发送一条MEET 信息。
(4)如果一切顺利节点 B 会收到节点 A 的 MEET 消息并为其创造一个 clusterNode 结构,将其加入到自己的 clusterState.nodes 字典中。
(5)之后节点 B 向节点 A 回复一个 PONG 消息。
(6)接收了 PONG 消息的节点 A 此时知道节点 B 成功接收了自己的 MEET 消息。
(7)节点 A 回复一个 PING 消息。
(8)节点 B 接收到 PING 消息,再回复一个 PONG 消息,握手完成。
在这里插入图片描述

槽指派

(1)redis 集群通过分片的方式来保存数据库中的键值对:键值对的整个数据库被分为了16384 个槽,数据库中的每个键都属于这 16384 槽中的一个,集群中的每个节点可以处理 0个或最多 16384 个槽。
(2)当数据库中的 16384 个槽都有人处理时集群处于上线状态,即使一个未处理也是下线状态。
(3)节点通过 CLUSTER ADDSLOTS 将一个或多个槽位分派给当前节点。
(4)clusterNode 结构中有一个 slots 数组,长度为 16384/8=2048 个字节,共包含了 16384个二进制位。如果 slots[i]为 1 则表面当前节点负责处理槽 i,若为 0 则不负责处理槽 i。
(5)因为取出和设置一个二进制位的时间复杂度为 O(1),所以检查节点是否处理某个槽或者将某个槽交给某个节点负责的时间复杂度都是 O(1)。
(6)clusterNode 结构的 numslots 属性记录了节点负责的槽的数量。
(7)一个节点除了将自己负责处理的槽记录在 clusterNode 结构的 slots 属性中之外,还会将自己的 slots 数组通过消息发送给集群中的其它节点,其它节点接收到消息后会设置自身 clusterState.nodes(因为 clusterState 结构的目的就是从当前节点的视角查看整个集群的信息)中找到发送消息的节点并更新它的 slots 数组状态。
(8)clusterState 结构中的 slots 数组记录了集群中所有 16384 个槽的指派信息。如果slots[i]指向 null 则 i 槽未分配给任何节点,否则 slots[i]会指向一个 clusterNode 结构,标识由该节点负责该槽。

CLUSTER ADDSLOTS 命令的实现

(1)将槽指派给某个节点后,clusterState.slots 数组中对应的位置指向此节点,clusterNode.slots 数组中对应的位置变为 1。
(2)然后节点会发送消息通知集群中的其它节点自己目前负责哪些槽位。

在集群中执行命令

(1)当客户端向节点发送键相关的命令时,接收命令的节点会计算出命令要处理的数据库键属于哪个槽,并检查这个槽是否指派给了自己。

  • 如果键所在的槽恰好是当前节点,那么节点会执行当前命令。
  • 如果键所在的槽并非当前节点,那么节点会向客户端返回一个 MOVED 错误并指引客户端转向正确的节点,并再次发送之前想要执行的命令。

(2)计算键所属槽的方法 CRC16(key) & 16383
(3)判断键是否由当前节点处理:如果 clusterState.slots[i]等于 clusterState.myself,那 么 说 明 i 由 当 前 节 点 负 责 , 节 点 可 以 执 行 客 户 端 命 令 ; 否 则 节 点 会 记 录clusterState.slots[i]指向的 clusterNode 所记录的 IP 和端口号,并向客户端返回 MOVED错误并携带真正存放数据节点的 IP 和端口号。
(4)集群中的节点只能使用 0 号数据库。
(5)除了将键值对保存在数据库中,节点还用 clusterState 中的 slots_to_keys 跳跃表来保存槽和键之间的关系(跳跃表在 redis 中的第二个应用,第一个是 zset 中)。跳跃表的分值是一个槽号而节点的成员就是一个数据库的键。

重新分片

(1)redis 重新分片操作是由 redis 集群管理软件 redis-trib 负责执行的。
(2)redis-trib 重新分片的步骤如下:

  • redis-trib 对目标节点发送 CLUSTER SETSLOT IMPORTING <source_id>让目标节点准备导入。
  • redis-trib 对原节点发送 CLUSTER SETSLOT MIGRATING <target_id>让源节点准备好将指定槽迁移至目标节点。
  • redis-trib 向源节点发送 CLUSTER GETKEYSINSLOT 获取最多 count个属于槽 slot 的键值对的键名。
  • 获得的每个键名都从源节点迁移至目标节点。
  • 重复执行上述两步直到原节点的所有属于槽 slot 的键值对都迁移成功。
  • redis-trib 像集群中的任意节点发送指派信息,该指派信息会通过消息发送至整个集群,最终集群中的所有节点都知道槽 slot 已经指派给目标节点。
    (3)重新分片期间可能出现被迁移槽的一部分键在源节点一部分在目标节点:源节点会先在自己的数据库中寻找,若没找着则返回一个 ASK 错误指引客户端转向正在导入槽的目标节点并再次发送之前的指令。

ASKING 命令

(1)ASKING 命令唯一作用就是打开该命令的客户端的 REDIS_ASKING 标识。
(2)正常情况下若发送一个命令给某一节点而该节点没有这个槽会返回一个 MOVED 错误,但是如果节点显示该槽正在被导入且客户端带有 REDIS_ASKING 标识则会破例执行一次关于这个槽的任务。
(3)客户端收到 ASK 错误并转向正在导入槽的节点时,客户端会先向节点发送一个 ASKING命令然后再重新发送想要执行的命令,因为客户端不发送 ASKING 命令而直接执行的话会被节点拒绝执行。
(4)ASK 错误和 MOVED 错误的区别,两者都会导致客户端转向,区别是:

  • MOVED 错误表示槽的负责权已经由一个节点转移至另一个节点,客户端收到 MOVED 错误之后的每次关于该槽的命令都会自动转向。
  • ASK 错误只是在迁移槽的过程中一种临时措施,只是当前一次将关于槽的命令转向错误所示的节点,不会对今后的命令产生影响。

复制与故障转移

(1)reids 集群中节点分为主节点和从节点,主节点负责处理槽,从节点负责复制主节点并在其下线之后代替下线的主节点处理命令请求。

(2)设置从节点 CLUSTER REPLICATE node_id让接收命令的节点成为 node_id 所指定节点的从节点,并开始复制主节点

(3)故障检测:集群中每个节点都会定期向集群中其它节点发送 PING 消息,如果接受到PING 消息的节点没有在规定时间内返回 PONG 消息,则会将此节点标记为疑似下线。集群中的各个节点会互发消息来交换集群中各个节点的状态信息。如果一个集群中半数以上的主节点都认为一个节点为疑似下线,则会将其标记为下线,将节点标记为下线的节点会向集群广播一条关于此主节点下线的消息,所有收到这条消息的节点也会将其标记为已下线。

(4)故障转移:当一个节点发现自己复制的节点处于下线状态了,会进行故障转移操作:

  • 复制下线主节点的所有从节点里面会有一个从节点被选中。
  • 被选中的从节点会执行 SLAVEOF no one 命令,成为新的主节点。
  • 新的主节点会撤销所有对已下线主节点的槽指派并将这些槽全部指向自己。
  • 新的主节点会发送一条 PONG 消息让其它节点知道自己已经成为了主节点并接管了已下线节点的所有槽。
  • 新的主节点开始接收并处理相关槽的命令,故障转移完成。

(5)选举新的主节点:新的主节点是通过选举产生的,具体投票策略与 Sentinel 节点选举头结点类似

消息

(1)集群中各点通过发送和接收消息来进行通信。
(2)节点消息主要有以下五种:MEET 消息、PING 消息、PONG 消息、FAIL 消息、PUBLISH 消息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值