Redis:分布式 - 集群-集群操作

时间:2024-10-14 11:11:02

此时可以连接任意一个端口的redis,比如6371

redis-cli -p 6371

此时不论连接上任意一个节点,都可以视作连接上了整个集群。

cluster nodes

执行以上命令,可以看到当前节点集群内的所有节点。

在这里插入图片描述


重定向

尝试插入数据:

在这里插入图片描述

报错了,因为当前集群发生了分片,每个分片都只能存储一部分数据,key1经过哈希运算,发现并不是这个节点可以存储的值,于是就报错了。

想要解决这个问题,可以在启动时加上-c选项,此时插入数据,会自动重定向到对应的节点。

redis-cli -c -p 6371

在这里插入图片描述

如图,每次操作数据是,如果该数据不属于当前分片,就会触发一次重定向,自动跳转到对应的客户端。命令行前面的端口号一直在改变,这就说明我们的客户端一直在切换。

但是redis中,有一些命令同时操作多个key,比如最后一个命令mget,此时又报错了。因为这几个key属于不同分片,那么就无法同时处理,因此在集群的情况下,最好不要一次性操作多个key


故障转移

如果在集群中,某一个分片的主节点宕机了,会发生什么?在部署集群时,并没有引入哨兵节点,但是集群也会完成哨兵的工作,如果主节点宕机了,集群会自动完成重新选主的过程

如图:

在这里插入图片描述

首先通过docker stop redis1,关掉了redis1节点,也就是xxx.101下线了,而这是一个主节点。登录6372端口的客户端,查看当前集群,可以发现xxx.106成为了新的主节点,而xxx.106原先是xxx.101的从节点。

在这里插入图片描述

重启redis1,其变为了reids6的从节点。

此处集群的故障转移,和哨兵的故障转移是有一些差别的,接下来就讲解集群中是如何完成故障转移的。

  • 故障判定

集群中的所有节点,都会周期性的使用心跳包进行通信

  1. 节点A 给 节点B 发送ping包,B 就会给 A 返回一个pong包,pingpong除了消息类型属性之外,其他部分都是一样的,这里包含了集群的配置信息:
    • 节点的id
    • 该节点从属于哪个分片
    • 是主节点还是从节点
    • 从属于谁
    • 持有哪些哈希槽的位图
  2. 每个节点,每秒钟都会给一些随机的节点发起 ping 包,而不是全发一遍,这样设定是为了避免在节点很多的时候,心跳包也非常多
  3. 当 节点A 给 节点B 发起 ping包,B不能如期回应的时候,此时 A 就会尝试重置和 B 的 tcp 连接,看能否连接成功,如果仍然连接失败,A 就会把 B 设为 PFAIL 状态,相当于主观下线
  4. A 判定 B为 PFAIL 之后,会通过 redis 内置的 Gossip 协议,和其他节点进行沟通,向其他节点确认 B的状态,每个节点都会维护一个自己的"下线列表",由于视角不同,每个节点的下线列表也不一定相同
  5. 此时A发现其他很多节点也认为B为 PFAIL,并且数目超过总集群个数的一半,那么A就会把B标记成 FAIL (相当于客观下线),并且把这个消息同步给其他节点,其他节点收到之后,也会把B标记成FAIL

至此,B 就彻底被判定为故障节点了。

  • 故障迁移

上述例子中,B 故障并且 A 把 B FAIL 的消息告知集群中的其他节点:

  • 如果 B 是从节点,那么不需要进行故障迁移
  • 如果 B是主节点,那么就会由 B 的从节点触发故障迁移

所谓故障迁移,就是指把从节点提拔成主节点,继续给整个redis 集群提供支持.具体流程如下:

  1. 从节点判定自己是否具有参选资格,如果从节点和主节点已经太久没通信,此时认为从节点的数据和主节点差异太大了,时间超过阈值,就失去竞选资格
  2. 具有资格的节点,就会先休眠一定时间,休眠时间=500ms基础时间+[0,500ms]随机时间+排名*1000msoffset 的值越大,则排名越靠前(越小)
  3. 如果某个节点的休眠时间到了,该节点就会给其他所有集群中的节点,进行拉票操作,但是只有主节点才有投票资格
  4. 每个主节点只有1票,当该节点收到的票数超过主节点数目的一半,就会晋升成主节点
  5. 新的主节点自己负责执行 slaveofno one,并且让同一分片中的其它节点执行 slaveof
  6. 最后,新的主节点会把自己成为主节点的消息,同步给其他集群的节点,大家也都会更新自己保存的集群结构信息

以上算法成为raft算法,其实和哨兵选主的目的是一样的,就是选出那个目前网络状态比较好的节点成为主节点,而网络状态的反映,就是休眠时间。

有些情况下,如果节点宕机,会导致整个集群宕机,这称为fail状态:

  1. 某个分片内部,所有的主节点和从节点都挂了
  2. 某个分片内部,主节点挂了没有从节点可以成为新的主节点
  3. 超过半数的主节点都挂了

集群扩容

  • 加入集群

想要给集群扩容,可以通过--cluster add-node选项:

redis-cli --cluster add-node 新增节点 集群任意节点
  • 新增节点:要增加到集群的节点
  • 集群任意节点:用于标识要加入哪一个集群

执行:

redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379

这样就可以把xxx.110节点加入到集群中,登入任意客户端查看:

在这里插入图片描述

可以看到,集群内部已经有xxx.110了,而且是一个主节点。但是仔细观察,可以发现其他节点末尾都有哈希槽的范围,但是新增的节点没有,说明新节点还没有分配。

  • 分配哈希槽

接下来就要给新节点分配哈希槽,同选项 --cluster reshard,注意是shard不是shared

redis-cli --cluster reshard 172.30.0.101:6379

执行后进入如下选项:

在这里插入图片描述

上面的S表示从节点,M表示主节点,在主节点的信息中,已经告知了每个主节点拥有的槽位个数。此处它询问要移动多少个slots,也就是哈希槽。

此处要移动4096个哈希槽给新节点,所以输入4096

在这里插入图片描述

随后它询问将这些哈希槽移动给哪一个节点,此时往上找哪一个master节点的哈希槽为0,复制他的ID。

在这里插入图片描述

最后询问,要从哪些节点中空出这些节点。如果选择all,那么就是从所有的现有节点平均提取。如果你希望自己指定,那么就复制那些节点的ID,最后以done结尾即可。

在这里插入图片描述

最后向用户确认,是否要这样执行。

最后进入任意客户端,查看集群现状:

在这里插入图片描述

可以看到,新节点获得了三个范围的哈希槽。

这里有一个小问题,这个搬运哈希槽的过程是比较久的,如果在搬运期间,用户访问数据是合法的吗?

这分情况,搬运过程中,大部分哈希槽是不用搬运的,如果用户访问这些哈希槽内的数据,那么可以正常访问。但是如果用户访问正在移动的哈希槽,那么就会失败了。

  • 添加从节点

目前添加了主节点,最后还要把从节点安排上,这通过 add-node命令配合--cluster-master-id完成:

redis-cli --cluster add-node 新节点 --cluster-slave --cluster-master-id 主节点的ID
  • --cluster-slave:这个选项指定新添加的节点将作为从节点
  • --cluster-master-id:这个选项后面跟着的是主节点的ID,表示该节点从属于哪一个节点

在这里插入图片描述

此时从属节点就成功加入集群了。