https://baijiahao.baidu.com/s?id=1663270958212268352&wfr=spider&for=pc
https://www.cnblogs.com/crazymakercircle/p/14282108.html
主从复制的过程
复制+哨兵模式的集群存在的问题
master多大的内存,就只能存这个多的数据。master无法横向扩容。
redis cluster > replication + sentinal
缓存节点的扩展和收缩
作为分布式部署的缓存节点总会遇到缓存扩容和缓存故障的问题。这就会导致缓存节点的上线和下线的问题。
由于每个节点中保存着槽数据,因此当缓存节点数出现变动时,这些槽数据会根据对应的虚拟槽算法被迁移到其他的缓存节点上。
如图所示,集群中本来存在“缓存节点 1”和“缓存节点 2”,此时“缓存节点 3”上线了并且加入到集群中。
此时根据虚拟槽的算法,由于新节点的加入,“缓存节点 1”和“缓存节点 2”中对应槽的数据会被被迁移到“缓存节点 3”上面。
针对节点扩容,新建立的节点需要运行在集群模式下,因此新建节点的配置最好与集群内其他节点配置保持一致。
新节点加入到集群的时候,作为孤儿节点是没有和其他节点进行通讯的。因此,其会采用 cluster meet 命令加入到集群中。
在集群中任意节点执行 cluster meet 命令让新节点加入进来。假设新节点是 192.168.1.1 5002,老节点是 192.168.1.1 5003,那么运行以下命令将新节点加入到集群中。
192.168.1.1 5003> cluster meet 192.168.1.1 5002
这个是由老节点发起的,有点老成员欢迎新成员加入的意思,也可以由新节点发起。新节点刚刚建立没有建立槽对应的数据,也就是说没有缓存任何数据。
如果这个节点是主节点,需要对其进行槽数据的扩容;如果这个节点是从节点,就需要同步主节点上的数据。总之就是要同步数据。
如图所示,由客户端发起节点之间的槽数据迁移,数据从源节点往目标节点迁移。
通过源节点和目标节点上执行命令就可以实现数据的迁移,通过cluster setslot {slot} node {targetNodeId} 命令通知对应的槽被分配到目标节点,并且广播这个信息给全网的其他主节点,更新自身的槽节点对应表。
既然有缓存服务器的上线操作,那么也有下线的操作。下线操作正好和上线操作相反,将要下线缓存节点的槽数据分配到其他的缓存主节点中。
迁移的过程也与上线操作类似,不同的是下线的时候需要通知全网的其他节点忘记自己,此时通过命令 cluster forget{downNodeId} 通知其他的节点。
当节点收到 forget 命令以后会将这个下线节点放到仅用列表中,那么之后就不用再向这个节点发送 Gossip 的 Ping 消息了。
故障发现和恢复
前面在谈到缓存节点扩展和收缩是提到,缓存节点收缩时会有一个下线的动作。
有些时候是为了节约资源,或者是计划性的下线,但更多时候是节点出现了故障导致下线。针对下线故障来说有两种下线的确定方式:
主观下线:当节点 1 向节点 2 例行发送 Ping 消息的时候,如果节点 2 正常工作就会返回 Pong 消息,同时会记录节点 1 的相关信息。同时接受到 Pong 消息以后节点 1 也会更新最近一次与节点 2 通讯的时间。如果此时两个节点由于某种原因断开连接,过一段时间以后节点 1 还会主动连接节点 2,如果一直通讯失败,节点 1 中就无法更新与节点 2 最后通讯时间了。此时节点 1 的定时任务检测到与节点 2 最好通讯的时间超过了cluster-node-timeout 的时候,就会更新本地节点状态,把节点 2 更新为主观下线。这里的 cluster-node-timeout 是节点挂掉被发现的超时时间,如果超过这个时间还没有获得节点返回的 Pong 消息就认为该节点挂掉了。这里的主观下线指的是,节点 1 主观的认为节点 2 没有返回 Pong 消息,因此认为节点 2 下线。只是节点 1 的主观认为,有可能是节点 1 与节点 2 之间的网络断开了,但是其他的节点依旧可以和节点 2 进行通讯,因此主观下线并不能代表某个节点真的下线了。
客观下线:由于 Redis Cluster 的节点不断地与集群内的节点进行通讯,下线信息也会通过 Gossip 消息传遍所有节点。因此集群内的节点会不断收到下线报告,当半数以上持有槽的主节点标记了某个节点是主观下线时,便会触发客观下线的流程。也就是说当集群内的半数以上的主节点,认为某个节点主观下线了,才会启动这个流程。这个流程有一个前提,就是直针对主节点,如果是从节点就会忽略。也就是说集群中的节点每次接受到其他节点的主观下线是都会做以下的事情。将主观下线的报告保存到本地的 ClusterNode 的结构中,并且针对主观下线报告的时效性进行检查,如果超过 cluster-node-timeout*2 的时间,就忽略这个报告。否则就记录报告内容,并且比较被标记下线的主观节点的报告数量大于等于持有槽的主节点数量的时候,将其标记为客观下线。
同时向集群中广播一条 Fail 消息,通知所有的节点将故障节点标记为客观下线,这个消息指包含故障节点的 ID。此后,群内所有的节点都会标记这个节点为客观下线,通知故障节点的从节点出发故障转移的流程,也就是故障恢复。
说白了,客观下线就是整个集群中有一半的节点都认为某节点主观下线了,那么这个节点就被标记为客观下线了。如果某个主节点被认为客观下线了,那么需要从它的从节点中选出一个节点替代主节点的位置。
此时下线主节点的所有从节点都担负着恢复义务,这些从节点会定时监测主节点是否下线。一旦发现下线会走如下的故障恢复流程:
①资格检查,每个节点都会检查与主节点断开的时间。如果这个时间超过了 cluster-node-timeoutcluster-slave-validity-factor(从节点有效因子,默认为 10),那么就没有故障转移的资格。
也就是说这个从节点和主节点断开的太久了,很久没有同步主节点的数据了,不适合成为新的主节点,因为成为主节点以后其他的从节点回同步自己的数据。
②触发选举,通过了上面资格的从节点都可以触发选举。但是出发选举是有先后顺序的,这里按照复制偏移量的大小来判断。
这个偏移量记录了执行命令的字节数。主服务器每次向从服务器传播 N 个字节时就会将自己的复制偏移量+N,从服务在接收到主服务器传送来的 N 个字节的命令时,就将自己的复制偏移量+N。
复制偏移量越大说明从节点延迟越低,也就是该从节点和主节点沟通更加频繁,该从节点上面的数据也会更新一些,因此复制偏移量大的从节点会率先发起选举。
③发起选举,首先每个主节点会去更新配置纪元(clusterNode.configEpoch),这个值是不断增加的整数。
在节点进行 Ping/Pong 消息交互式也会更新这个值,它们都会将最大的值更新到自己的配置纪元中。
这个值记录了每个节点的版本和整个集群的版本。每当发生重要事情的时候,例如:出现新节点,从节点精选。都会增加全局的配置纪元并且赋给相关的主节点,用来记录这个事件。
说白了更新这个值目的是,保证所有主节点对这件“大事”保持一致。大家都统一成一个配置纪元(一个整数),表示大家都知道这个“大事”了。
更新完配置纪元以后,会想群内发起广播选举的消息(FAILOVER_AUTH_REQUEST)。并且保证每个从节点在一次配置纪元中只能发起一次选举。
④投票选举,参与投票的只有主节点,从节点没有投票权,超过半数的主节点通过某一个节点成为新的主节点时投票完成。
如果在 cluster-node-timeout2 的时间内从节点没有获得足够数量的票数,本次选举作废,进行第二轮选举。
这里每个候选的从节点会收到其他主节点投的票。在第2步领先的从节点通常此时会获得更多的票,因为它触发选举的时间更早一些。
获得票的机会更大,也是由于它和原主节点延迟少,理论上数据会更加新一点。
⑤当满足投票条件的从节点被选出来以后,会触发替换主节点的操作。新的主节点别选出以后,删除原主节点负责的槽数据,把这些槽数据添加到自己节点上。
并且广播让其他的节点都知道这件事情,新的主节点诞生了。