Redis之哨兵模式
Sentinel(哨兵)是redis高可用的解决方案:由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进行下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。
对每个被监视的主服务器来说,Sentinel会创建两个连向主服务器的异步网络连接:
- 一个是命令连接,这个连接专门用来向主服务器发送命令,并接受命令回复
- 一个是订阅连接,这个连接专门用来订阅主服务器的——sentinel_:hello频道
为什么需要两个连接?
订阅连接用来接收主服务器的消息,命令连接用来向主服务器发送命令(此时Sentinel相当于主服务器的一个客户端)
Sentinel会默认10秒1次,通过命令连接向主服务器发送info命令,获得主服务器以及主服务器属下的从服务器信息。
当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为这个新的从服务器创建相应的实例结构之外,Sentinel还会创建连接到从服务器的命令连接和订阅连接。Sentinel也会以10秒1次向从服务器发送info命令,获得从服务器的响应信息。
当一个Sentinel与一个主服务器或者从服务器建立起订阅连接之后,对于监视同一个服务器的多个Sentinel来说,一个Sentinel发送的信息会被其他Sentinel接收到,这些信息会被其他Sentinel接收到,这些信息会被用于更新其他Sentinel对发送信息Sentinel的认知,也会被用于更新其他Sentinel对被监视服务器的认知。
当Sentinel通过频道信息发现一个新的Sentinel时,会创建一个连向Sentinel的命令连接,而新的Sentinel也同样会创建连向这个Sentinel命令连接。需要注意的是Sentinel之间不需要订阅连接,原因在于Sentinel与主服务器,从服务器建立订阅连接的目的就是为了获得其他Sentinel的信息,而Sentinel之间只需要通信即可。
判断服务器下线
Sentinel会以每秒1次的频率向与它创建了命令连接的实例(包括主服务器,从服务器,其他Sentinel)发送PING命令,如果在指定时间长度内,该实例连续向Sentinel返回无效回复或者不回复,则Sentinel主观认为该实例下线。
当一个Sentinel认为一个实例主观下线后,会询问其他Sentinel该实例是否下线,当认为下线的Sentinel数目超过阈值后,则认为该实例客观下线。
选举领头Sentinel
当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举一个领头Sentinel
每个发现主服务器下线的Sentinel节点都会给其他节点发送通知,要求对方选举自己为局部领头,遵循先来后到的原则,一旦节点选择了局部领头就不会再选举其他节点为局部领头,如果某个节点被半数以上Sentinel节点选举为局部领头,则成为领头Sentinel。如果在给定的时间内,没有选举出领头Sentinel则会在一段时间后重新选举直到选出领头Sentinel
故障转移
在选举出领头Sentinel后,领头Sentinel对以下线的主服务器执行故障转移操作,该操作包含三个步骤:
1.在已下线的主服务器属下的所有到的从服务器里面,挑选出一个从服务器,并将其转化为主服务器
2.让已下线的主服务器属下的所有从服务器改为复制新的主服务器
3.将以下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,它会成为新的主服务器的从服务器
如何选举主服务器?
首先从主服务器的从服务器中排除不活跃的服务器(已断线,长时间未回复领头Sentinel的info),然后根据从服务器的优先级,选取优先级最高的服务器,如果优先级相同,则选举复制偏移量最大的服务器,如果复制偏移量相同,则选举id最小的服务器