十二、redis集群(⑤出浅)

导读

前面文章【一、深入理解redis之需要掌握的知识点 】中,我们对redis需要学习的内容框架进行了一个梳理。

二、redis中String和List两种数据类型和应用场景 】、【二、redis中Hash、Set、SortedSet应用场景 】两篇文章我们对redis中String、List、Hash、Set、SortedSet五种数据类型做了一下讲解,并且对他们各自的应用场景进行了介绍。

三、redis数据存储之跳跃表(SKIP LIST) 】深入学习了支撑SortedSet排序背后的数据结构,跳跃表;

【四、redis持久化之RDB与AOF 】学习了redis中的两种持久化策略:RDB(快照)和AOF(追加日志);
五、redis集群进化过程 】文章中我们学习了redis集群的进化过程,包括解决单点故障问题和性能瓶颈问题等。
六、redis中AKF问题解决方案 】讲解了Redis使用及集群进化过程中AKF问题的解决方案。
七、redis中CAP问题解决方案-Paxos理论过半通过 】我们讲解了Redis使用过程中出现CAP问题的解决方案,以及初步认识Paxos分布式一致性协议。
八、redis中布式锁的实现及原理 】讲解了redis中布式锁的理论、原理及解决方案。

九、redis缓存的回收策略-LRU算法】我们讲解了redis中如何配置缓存回收策略及回收策略的几种模式,另外还要讲解回收策略的执行过程和redis中实际使用的回收策略。

十、redis中的哨兵模式(Sentinel)】中讲解了Redis中的哨兵模式,包括如何配置哨兵模式、哨兵模式下的客观下线和主观下线及故障转移策略等。
十一、redis中的事物】讲解了redis中的事物,包括如何开启事物,如何使用事物做日常操作等。

从【十二、redis集群(①初识)】开始,我们学习redis集群,包括redis集群的使用、搭建及redis集群内部原理等。
十二、redis集群(①初识)】中主要先初识redis集群,了解他的优势及模型等;
十二、redis集群(②相遇)】文章中我们主要学习,如何搭建redis集群、如何使用redis集群、redis集群中数据的键是如何分配的以及redis集群中每个节点的属性;
十二、redis集群(③深入)】我们开始深入了解redis集群节点的拓扑结构以及节点之间数据交互及重定向等;
十二、redis集群(④浅出)】中我们学习了redis集群中的失效检测和redis中的逻辑时钟-epoch等。
在这里插入图片描述

本章我们将要学习redis中的选举策略及集群中服务器之间哈希槽的传播。
如果大家在工作、学习、面试中针对redis还有什么疑问或者其他问题,可以评论区告诉我。为了保证可以连续不间断地获取最新的技术分析及讲解,建议关注本博客【不吃_花椒】。

集群中的选举

丛节点的选举和提升
从节点的选举和提升都是由从节点处理的,主节点会投票要提升哪个从节点。一个从节点的选举是在主节点被至少一个具有成为主节点必备条件的从节点标记为 FAIL 的状态的时候发生的。
当以下条件满足时,一个从节点可以发起选举:

  • 该从节点的主节点处于 FAIL 状态。
  • 这个主节点负责的哈希槽数目不为零。
  • 从节点和主节点之间的重复连接(replication link)断线不超过一段给定的时间,这是为了确保从节点的数据是可靠的。
  • 一个从节点想要被推选出来,那么第一步应该是提高它的 currentEpoch 计数,并且向主节点们请求投票。

从节点通过广播一个 FAILOVER_AUTH_REQUEST 数据包给集群里的每个主节点来请求选票。然后等待回复(最多等 NODE_TIMEOUT 这么长时间)。一旦一个主节点给这个从节点投票,会回复一个 FAILOVER_AUTH_ACK,并且在 NODE_TIMEOUT * 2 这段时间内不能再给同个主节点的其他从节点投票。在这段时间内它完全不能回复其他授权请求。
从节点会忽视所有带有的时期(epoch)参数比 currentEpoch 小的回应(ACKs),这样能避免把之前的投票的算为当前的合理投票。
一旦某个从节点收到了大多数主节点的回应,那么它就赢得了选举。否则,如果无法在 NODE_TIMEOUT 时间内访问到大多数主节点,那么当前选举会被中断并在 NODE_TIMEOUT * 4 这段时间后由另一个从节点尝试发起选举。
从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一点点延迟,这段延迟是这么计算的:

DELAY = 500 milliseconds + random delay between 0 and 500 milliseconds +
        SLAVE_RANK * 1000 milliseconds.

固定延时(fixed delay)确保我们会等到 FAIL 状态在集群内广播后,否则若从节点尝试发起选举,主节点们仍然不知道那个主节点已经 FAIL,就会拒绝投票。
data_age / 10 参数是用来让从节点有时间去获得新鲜数据(在与主节点断线的这一小段时间内)。 随机延时(random delay)是用来添加一些不确定因素以减少多个从节点在同一时间发起选举的可能性,因为若同时多个从节点发起选举或许会导致没有任何节点赢得选举,要再次发起另一个选举的话会使集群在当时变得不可用。
一旦有从节点赢得选举,它就会开始用 ping 和 pong 数据包向其他节点宣布自己已经是主节点,并提供它负责的哈希槽,设置 configEpoch 为 currentEpoch(选举开始时生成的)。
为了加速其他节点的重新配置,该节点会广播一个 pong 包 给集群里的所有节点(那些现在访问不到的节点最终也会收到一个 ping 包或 pong 包,并且进行重新配置)。
其他节点会检测到有一个新的主节点(带着更大的configEpoch)在负责处理之前一个旧的主节点负责的哈希槽,然后就升级自己的配置信息。 旧主节点的从节点,或者是经过故障转移后重新加入集群的该旧主节点,不仅会升级配置信息,还会配置新主节点的备份。

主节点回复从节点的投票请求
在上一节中我们讨论了从节点是如何被选举上的,这一节我们将从主节点的角度解释在为给定从节点投票的时候发生了什么。
主节点接收到来自于从节点、要求以 FAILOVER_AUTH_REQUEST 请求的形式投票的请求。 要授予一个投票,必须要满足以下条件:

  1. 在一个给定的时段(epoch)里,一个主节点只能投一次票,并且拒绝给以前时段投票:每个主节点都有一个lastVoteEpoch域,一旦认证请求数据包(auth request packet)里的 currentEpoch小于lastVoteEpoch,那么主节点就会拒绝再次投票。当一个主节点积极响应一个投票请求,那么 lastVoteEpoch会相应地进行更新。
  2. 一个主节点投票给某个从节点当且仅当该从节点的主节点被标记为 FAIL。
  3. 如果认证请求里的currentEpoch 小于主节点里的 currentEpoch
    的话,那么该请求会被忽视掉。因此,主节点的回应总是带着和认证请求一致的currentEpoch。如果同一个从节点在增加
    currentEpoch后再次请求投票,那么保证一个来自于主节点的、旧的延迟回复不会被新一轮选举接受。

下面的例子是没有依据这个规则引发的事件:

  1. 主节点的 currentEpoch 是 5, lastVoteEpoch 是 1(在几次失败的选举后这也许会发生的)
  2. 从节点的 currentEpoch 是 3。
  3. 从节点尝试用 epoch 值为 4(3+1)来赢得选票,主节点回复 ok,里面的 currentEpoch 是 5,可是这个回复延迟了。
  4. 从节点尝试用 epoch 值为 5(4+1)来再次赢得选票,收到的是带着 currentEpoch 值为 5
    的延迟回复,这个回复会被当作有效的来接收。
  1. 主节点若已经为某个失效主节点的一个从节点投票后,在经过 NODE_TIMEOUT * 2
    时间之前不会为同个失效主节点的另一个从节点投票。这并不是严格要求的,因为两个从节点用同个 epoch来赢得选举的可能性很低,不过在实际中,系统确保正常情况当一个从节点被选举上,那么它有足够的时间来通知其他从节点,以避免另一个从节点发起另一个新的选举。
  2. 主节点不会用任何方式来尝试选出最好的从节点,只要从节点的主节点处于 FAIL 状态并且投票主节点在这一轮中还没投票,主节点就能进行积极投票。
  3. 若一个主节点拒绝为给定从节点投票,它不会给任何负面的回应,只是单纯忽略掉这个投票请求。
  4. 主节点不会授予投票给那些 configEpoch 值比主节点哈希槽表里的 configEpoch更小的从节点。记住,从节点发送了它的主节点的 configEpoch 值,还有它的主节点负责的哈希槽对应的位图。
本质上来说,这意味着,请求投票的从节点必须拥有它想要进行故障转移的哈希槽的配置信息,
而且信息应该比它请求投票的主节点的配置信息更新或者一致。

从节点选举的竞争情况
这一节解释如何使用 epoch 概念来使得从节点提升过程对分区操作更有抵抗力。

  • 主节点不是无限期地可达。它拥有三个从节点 A,B,C。

  • 从节点 A 赢得了选举并且被推选为主节点。

  • 一个分区操作使得集群中的大多数节点无法访问节点 A。

  • 节点 B 赢得了选举并且被推选为主节点。

  • 一个分区操作使得集群中大多数节点无法访问节点 B。

  • 之前分区操作的问题被修复了,节点 A 又恢复可访问状态。

此刻,节点 B 仍然失效,节点 A 恢复可访问,会与节点 C 竞选去获得选票对节点 B 进行故障转移。
这两个有同样的哈希槽的从节点最终都会请求被提升,然而由于它们发布的 configEpoch 是不一样的,而且节点 C 的 epoch 比较大,所以所有的节点都会把它们的配置更新为节点 C 的。
节点 A 会从来源于节点 C(负责同样哈希槽的节点)的 ping 包中检测出节点 C 的 epoch 是更大的,所以它会重新设置自己为节点 C 的一个从节点。

集群中服务器之间哈希槽的传播

服务器哈希槽信息的传播规则
Redis 集群很重要的一个部分是用来传播关于集群节点负责哪些哈希槽的信息的机制。这对于新集群的启动和提升从节点来负责处理哈希槽(它那失效的主节点本该处理的槽)的能力来说是必不可少的。
个体持续交流使用的 ping 包和 pong 包都包含着一个头部,这个头部是给发送者使用的,为了向别的节点宣传它负责的哈希槽。这是主要用来传播变更的机制,不过集群管理员手动进行重新配置是例外(比如为了在主节点间移动哈希槽,通过 redis-trib 来进行手动碎片整理)。
当一个新的 Redis 集群节点创建的时候,它的本地哈希槽表(表示给定哈希槽和给定节点 ID 的映射关系表)被初始化,每个哈希槽被置为 nil,也就是,每个哈希槽都是没赋值的。

一个节点要更新它的哈希槽表所要遵守的第一个规则如下:

规则 1:如果一个哈希槽是没有赋值的,然后有个已知节点认领它,那么我就会修改我的哈希槽表,把这个哈希槽和这个节点关联起来。
由于这个规则,当一个新集群被创建的时候,只需要手动给哈希槽赋值上(通常是通过 redis-trib 命令行工具使用 CLUSTER 命令来实现)负责它的主节点,然后这些信息就会迅速在集群中传播开来。
然而,当一个配置更新的发生是因为一个从节点在其主节点失效后被提升为主节点的时候,这个规则显然还不足够。新的主节点会宣传之前它做从节点的时候负责的哈希槽,但从其他节点看来这些哈希槽并没有被重新赋值,所以如果它们只遵守第一个规则的话就不会升级配置信息。
由于这个原因就有第二个规则,是用来把一个已赋值给以前节点的哈希槽重新绑定到一个新的认领它的节点上。规则如下:
规则 2:如果一个哈希槽已经被赋值了,有个节点它的 configEpoch 比哈希槽当前拥有者的值更大,并且该节点宣称正在负责该哈希槽,那么我们会把这个哈希槽重新绑定到这个新节点上。
因为有这第二个规则,所以集群中的所有节点最终都会同意哈希槽的拥有者是所有声称拥有它的节点中 configEpoch 值最大的那个。

UPDATE 消息
上面描述的传播哈希槽配置信息的系统只使用节点间交换信息的普通 ping 包和 pong 包。 这要求存在一个节点(可以是负责给定哈希槽的主节点或从节点)拥有更新后的配置信息,因为节点是在 ping 包和 pong 包头部中发送它们自己的配置信息。
然而也存在例外。当有一个节点,它是唯一一个负责处理给定哈希槽的节点,有可能在分区操作后它恢复正常,但拥有的配置信息是过时的。
例子:一个给定的哈希槽是由节点 A 和 B 负责的。节点 A 是一个主节点,然后它在某个时刻失效了,所以节点 B 被提升为主节点。过了一段时间节点 B 也失效了,集群没有其他备份节点可以来处理这个哈希槽,所以只能开始修复操作。
在一段时间过后节点 A 恢复正常了,并且作为一个可写入的主节点重新加入集群,但它的配置信息是过时的。此时没有任何备份节点能更新它的配置信息。这就是 UPDATE 消息存在的目的:当一个节点检测到其他节点在宣传它的哈希槽的时候是用一份过时的配置信息,那么它就会向这个节点发送一个 UPDATE 消息,这个消息包含新节点的 ID 和它负责的哈希槽(以 bitmap 形式发送)。
注意:目前更新配置信息可以用 ping 包/ pong 包,也可以用 UPDATE 消息,这两种方法是共享同一个代码路径(code path)。这两者在更新一个带有老旧信息的节点的配置信息时会有功能上的重复。然而这两种机制都是非常有用的,因为 ping / pong 包在一段时间后能填充(populate)新节点的哈希槽路由表,而 UPDATE 消息只是在一个过时配置信息被检测出来时才被发送出去,并且只覆盖那些需要修复的错误配置信息。

如需了解更多更详细内容也可关注本人CSDN博客:不吃_花椒

后续redis中将要讲解的内容梳理

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

往期文章

Redis

一、深入理解redis之需要掌握的知识点

二、redis中String和List两种数据类型和应用场景

二、redis中基础数据类型Hash、Set、SortedSet及其应用场景

三、redis数据存储之跳跃表(SKIP LIST)

四、redis持久化之RDB与AOF

五、redis集群进化过程简单梳理

六、redis中AKF问题解决方案

七、redis中CAP问题解决方案-Paxos理论过半通过

八、redis中布式锁的实现及原理

九、redis缓存的回收策略-LRU算法

十、redis中的哨兵模式(Sentinel)

十一、redis中的事物

十二、redis集群(①初识)

十二、redis集群(②相遇)

十二、redis集群(③深入)

十二、redis集群(④浅出)

Java集合

一、深入理解-Java集合初篇

二、Jdk1.7和1.8中HashMap数据结构及源码分析

三、JDK1.7和1.8HashMap数据结构及源码分析-续

四、深入理解Java中的HashMap「网易面试快答」

五、深入理解JDK1.7中HashMap哈希冲突解决方案

六、深入理解JDK1.8中HashMap哈希冲突解决方案

七、JDK1.7中HashMap扩容机制

八、JDK1.8中HashMap扩容机制

Java-IO体系

一、C10K问题经典问答

二、java.nio.ByteBuffer用法小结

三、Channel 通道

四、Selector选择器

五、Centos-Linux安装nc

六、windows环境下netcat的安装及使用

七、IDEA的maven项目的netty包的导入(其他jar同)

八、JAVA IO/NIO

九、网络IO原理-创建ServerSocket的过程

十、网络IO原理-彻底弄懂IO

十一、JAVA中ServerSocket调用Linux系统内核

十二、IO进化过程之BIO

十三、Java-IO进化过程之NIO

十四、使用Selector(多路复用器)实现Netty中Reactor单线程模型

十五、使用Selector(多路复用器)实现Netty中Reactor主从模型

十六、Netty入门服务端代码

十七、IO进化过程之EVENT(EPOLL-事件驱动异步模型)

如需了解更多更详细内容也可关注本人CSDN博客:不吃_花椒

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值