redis-sentinel简单看分布式高可用和一致性的取舍

1,884

redis-sentinel

Redis Sentinel 是一个分布式系统,为Redis提供高可用性解决方案。可以理解哨兵机制就是在复制基础上的一套监管系统,能及时的进行故障转移。

image.png

流言协议 (gossip protocols)

sentinel集群判断master是否下线是使用流言协议。

  • 每个Sentinel进程会以每秒一次的频率向已知的主服务器、从服务器以及其他的Sentinel实例发送一个PING命令

  • 每个实例(instance)距离最后一次有效回复PING命令的时间超过down-after-milliseconds选项所指定的值,那么该实例会被标记为主观下线。一个有效回复可以是:+PONG-LOADING或者-MASTERDOWN

  • 如果一个Master主服务器被标记为主观下线,那么监视该主服务器的所有的Sentinel会以每秒一次的频率确认主服务器的确是进入主线下线状态

  • 如果有足够数量的Sentinel(至少达到配置文件指定的数量)在指定时间范围内确认一个Master主服务器为主观下线状态,那么该主服务器被标记为客观下线

  • 没有足够数量的Sentinel同意主服务器下线,主服务器的客观下线状态会被移除;当主服务器重新向Sentinel的PING命令返回有效回复,主服务器的主观下线状态就会被移除

投票协议(agreement protocols)

主观下线:所谓主观下线,就是单个sentinel认为某个服务下线(有可能是接收不到订阅,之间的网络不通等等原因)。 客观下线:当主观下线的节点是主节点时,此时该哨兵3节点会通过指令sentinel is-masterdown-by-addr寻求其它哨兵节点对主节点的判断,如果其他的哨兵也认为主节点主观线下了,则当认为主观下线的票数超过了quorum(选举)个数,此时哨兵节点则认为该主节点确实有问题,这样就客观下线了,大部分哨兵节点都同意下线操作,也就说是客观下线。

如果主节点被判定为客观下线之后,就要选取一个哨兵节点来完成后面的故障转移工作,选举出一个leader的流程如下:

a)每个在线的哨兵节点都可以成为领导者,当它确认(比如哨兵3)主节点下线时,会向其它哨兵发is-master-down-by-addr命令,征求判断并要求将自己设置为领导者,由领导者处理故障转移;

b)而每个sentinel节点在收到一个”sentinel is-master-down-by addr”命令时,只允许给第一个节点投票,其他节点的该命令都会被拒绝;

c)如果哨兵3发现自己在选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举…………

在从节点(slave node) 中选择新的主节点(master node)

sentinel状态数据结构中保存了主服务的所有从服务信息,领头sentinel按照如下的规则从从服务列表中挑选出新的主服务

  1. 过滤掉主观下线的节点
  2. 选择slave-priority最高的节点,如果有则返回没有就继续选择
  3. 选择出复制偏移量最大的系节点,因为复制偏移量越大则数据复制的越完整,如果有就返回了,没有就继续
  4. 选择run_id最小的节点

更新主从状态

通过slaveof no one命令,让选出来的从节点成为主节点;并通过slaveof命令让其他节点成为其从节点。

将已下线的主节点设置成新的主节点的从节点,当其回复正常时,复制新的主节点,变成新的主节点的从节点.

配置传播

一旦一个sentinel成功地对一个master进行了failover,它将会把关于master的最新配置通过广播形式通知其它sentinel,其它的sentinel则更新对应master的配置。

一个faiover要想被成功实行,sentinel必须能够向选为master的slave发送SLAVE OF NO ONE命令,然后能够通过INFO命令看到新master的配置信息。

当将一个slave选举为master并发送SLAVE OF NO ONE`后,即使其它的slave还没针对新master重新配置自己,failover也被认为是成功了的,然后所有sentinels将会发布新的配置信息。

新配在集群中相互传播的方式,就是为什么我们需要当一个sentinel进行failover时必须被授权一个版本号的原因。

每个sentinel使用##发布/订阅##的方式持续地传播master的配置版本信息,配置传播的##发布/订阅##管道是:__sentinel__:hello

因为每一个配置都有一个版本号,所以以版本号最大的那个为标准。

举个栗子:假设有一个名为mymaster的地址为192.168.1.50:6379。一开始,集群中所有的sentinel都知道这个地址,于是为mymaster的配置打上版本号1。一段时候后mymaster死了,有一个sentinel被授权用版本号2对其进行failover。如果failover成功了,假设地址改为了192.168.1.50:9000,此时配置的版本号为2,进行failover的sentinel会将新配置广播给其他的sentinel,由于其他sentinel维护的版本号为1,发现新配置的版本号为2时,版本号变大了,说明配置更新了,于是就会采用最新的版本号为2的配置。

这意味着sentinel集群保证了第二种活跃性:一个能够互相通信的sentinel集群最终会采用版本号最高且相同的配置。

总结

redis sentinel本质上是实现故障摘除,自动恢复,也就是提高系统可用性,一致性模型为最终一致性,依赖广播获取配置信息,集群中每个sentinel最终都会采用最高版本的配置。