由一个或多个Sentinel实例(instance)组成的Sentinel系统(system)可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。
大致流程
一个Sentinel正在监视主服务器和属下的所有从服务器
image.png
假如这时,主服务器进入下线状态,那么从服务器server2、server3、server4对主服务器的复制操作将被中止,并且Sentinel系统会察觉到server1已下线。(下图1)
当server1的下线时长超过用户设定的下线时长上限时,Sentinel系统就会对server1执行故障转移操作∶
首先,Sentinel系统会挑选server1属下的其中一个从服务器,并将这个被选中的从服务器升级为新的主服务器。(下图2)
之后,Sentinel系统会向server1属下的所有从服务器发送新的复制指令,让它们成为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障转移操作执行完毕。(下图2)
另外,Sentinel还会继续监视已下线的server1,并在它重新上线时,将它设置为新的主服务器的从服务器。(下图3)
image.png
image.png
image.png
各部分细节
image.png启动并初始化Sentinel
启动Sentinel的命令
redis-sentinel /path/to/your/sentinel.conf
或者
redis-server /path/to/your/senttiel.conf --sentinel
image.png
下面是需要解释的
初始化服务器
不过,因为Sentinel执行的工作和普通Redis服务器执行的工作不同,所以Sentinel的初始化过程和普通Redis服务器的初始化过程并不完全相同。
例如,普通服务器在初始化时会通过载入RDB文件或者AOF文件来还原数据库状态,但是因为Sentinel并不使用数据库,所以初始化Sentinel时就不会载入RDB文件或者AOF文件。
image.png
PING、SENTINEL、INFO、SUBSCRIBE、UNSUBSCRIBE、PSUBSCRIBE和 PUNSUBSCRIBE 这七个命令就是客户端可以对Sentinel执行的全部命令了。
创建连向主服务器的网络连接
Sentinel成为主服务器的客户端,它可以向主服务器发送命令,并从命令回复中获取相关的信息。
image.png
对于每个被 Sentinel监视的主服务器来说,Sentinel会创建两个连向主服务器的异步网络连接∶
一个是命令连接,这个连接专门用于向主服务器发送命令,并接收命令回复。另一个是订阅连接,这个连接专门用于订阅主服务器的sentinel:hello频道。
获取主服务器的信息
到这里,创建初始化Sentinel服务器就已经完成了。
Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息。
INFO命令的回复包含如下信息:
一方面是关于主服务器本身的信息,包括run_id域记录的服务器运行ID,以及role域记录的服务器角色;
另一方面是关于主服务器属下所有从服务器的信息,每个从服务器都由一个"slave"字符串开头的行记录,每行的ip=域记录了从服务器的IP地址,而port=域则记录了从服务器的端口号。根据这些IP地址和端口号,Sentinel无须用户提供从服务器的地址信息,就可以自动发现从服务器。
根据这些信息,Sentinel会对主服务器的实例结构进行更新
# Server
run_id:7611c59dc3a29aa6fa0609f841bb6a1019008a9c
# Replication role:master ...
slave0:ip=127.0.0.1,port=1111,state=online,offset=43,lag=0
slave1:ip=127.0.0.1,port=22222,state=online,offset=43,lag=0
slave2:ip=127.0.0.1,port=33333,state=online,offset=43,lag=0 ···
# Other sections ···
获取从服务器的信息
当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为这个新的从服务器创建相应的实例结构之外,Sentinel还会创建连接到从服务器的命令连接和订阅连接。
在创建命令连接之后,Sentinel在默认情况下,会以每十秒一次的频率通过命令连接向从服务器发送INFO命令,并获得类似于以下内容的回复∶
# Server · · ·
run id:32be0699dd27b410f7c90dada3
fab17f97899f ···
Replication role:slave
master host:127.0.0.1
master_port:6379
master_link_status:up
slave_repl offset:11887
slave priority:100
#Other sections ···
可以根据INFO命令的回复得到:
从服务器的运行ID run_id。从服务器的角色 role。
主服务器的IP地址 master_host,以及主服务器的端口号master_port。
主从服务器的连接状态 master_link_status。
从服务器的优先级 slave_priority。
从服务器的复制偏移量 slave_repl_offset。
根据这些信息,Sentinel会对从服务器的实例结构进行更新
向主服务器和从服务器发送信息
在默认情况下,Sentinel会以每两秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送以下格式的命令∶
PUBLISH _sentinel__:hello "<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>"
其中以s_开头的参数记录的是Sentinel本身的信息.
而m_开头的参数记录的则是主服务器的信息。如果Sentinel正在监视的是主服务器,那么这些参数记录的就是主服务器的信息;如果Sentinel 正在监视的是从服务器,那么这些参数记录的就是从服务器正在复制的主服务器的信息。
image.png
image.png
接收来自主服务器和从服务器的频道信息
对于每个与Sentinel连接的服务器,Sentinel既通过命令连接向服务器的sentinel_∶hello频道发送信息,又通过订阅连接从服务器的sentinel∶hello 频道接收信息.
image.png
对于监视同一个服务器的多个Sentinel 来说,一个Sentinel发送的信息会被其他Sentinel接收到,这些信息会被用于更新其他Sentinel对发送信息Sentinel的认知,也会被用于更新其他Sentinel对被监视服务器的认知。
检测主观下线状态
在默认情况下,Sentinel会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他Sentinel在内)发送PING命令,并通过实例返回的PING命令回复来判断实例是否在线。
实例对PING命令的回复可以分为以下两种情况∶
有效回复∶实例返回+PONG、-LOADING、-MASTERDOWN 三种回复的其中一种。
无效回复∶实例返回除 +PONG、-LOADING、-MASTERDOWN三种回复之外的其他回复,或者在指定时限内没有返回任何回复。
Sentinel 配 置 文 件 中 的 down-after-milliseconds选项指定了Sentinel判断实例进入主观下线所需的时间长度∶如果一个实例在down-after-milliseconds毫秒内,连续向Sentinel返回无效回复,那么Sentinel 会修改这个实例所对应的实例结构,在结构的flags属性中打开SRI_S_DOWN标识,以此来表示这个实例已经进入主观下线状态。
用户设置的down-after-milliseconds选项的值,不仅会被Sentinel用来判断主服务器的主观下线状态,还会被用于判断主服务器属下的所有从服务器,以及所有同样监视这个主服务器的其他Sentinel的主观下线状态。
检测客观下线状态
当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一主服务器的其他Sentinel进行询问,看它们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。当Sentinel从其他Sentinel那里接收到足够数量的已下线判断之后,Sentinel就会将从服务器判定为客观下线,并对主服务器执行故障转移操作。
发送SENTINEL is-master-down-by-addr命令询问其他Sentinel是否同意主服务器已下线
SENTINEL is-master-down-by-addr<ip><port><current epoch><runid>
image.png
接收 SENTINEL is-master-down-by-addr命令并回复
当一个Sentinel(目标Sentinel)接收到另一个Sentinel(源Sentinel)发来的SENTINEL is-master-down-by命令时,目标Sentinel会分析并取出命令请求中包含的各个参数,并根据其中的主服务器IP和端口号,检查主服务器是否已下线,然后向源Serntinel返回一条包含三个参数的Multi Bulk 回复作为SENTINEL is-master-down-by命令的回复
1)<down_state>
2)<leader_runid>
3)<leader_epoch>
image.png
接收 SENTINEL is-master-down-by-addr的回复
根据其他Sentinel发回的SENTINEL is-master-down-by-addr命令回复,Sentinel 将统计其他Sentinel同意主服务器已下线的数量,当这一数量达到配置指定的判断客观下线所需的数量时,Sentinel会将主服务器实例结构flags属性的SRI_O_DOWN标识打开,表示主服务器已经进入客观下线状态.
选举领头的Sentinel
当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举出一个领头Sentinel,并由领头Sentinel对下线主服务器执行故障转移操作。
选举领头Sentinel的规则
1.所有在线的Sentinel都有被选为领头Sentinel的资格,换句话说,监视同一个主服务器的多个在线Sentinel中的任意一个都有可能成为领头Sentinel。
2.每次进行领头Sentinel选举之后,不论选举是否成功,所有Sentinel的配置纪元(configuration epoch)的值都会自增一次。配置纪元实际上就是一个计数器,并没有什么特别的。
3.在一个配置纪元里面,所有Sentinel都有一次将某个Sentinel设置为局部领头Sentinel的机会,并且局部领头一旦设置,在这个配置纪元里面就不能再更改。每个发现主服务器进人客观下线的Sentinel都会要求其他Sentinel将自己设置为局部领头Sentinel。
4.当一个Sentinel(源Sentinel)向另一个Sentinel(目标Sentinel)发送SENTINEL is-master-down-by-addr命令,并且命令中的runid参数不是·符号而是源Sentinel的运行ID时,这表示源Sentinel要求目标Sentinel将前者设置为后者的局部领头Sentinel。
5.Sentinel设置局部领头Sentinel的规则是先到先得∶最先向目标 Sentinel发送设置要求的源Sentinel将成为目标Sentinel的局部领头Sentinel,而之后接收到的所有设置要求都会被目标 Sentinel 拒绝。
6.目标 Sentinel在接收到SENTINEL is-master-down-by-addr命令之后,将向源Sentinel返回一条命令回复,回复中的leader_runid参数和leader_epoch 参数分别记录了目标Sentinel的局部领头 Sentinel的运行ID和配置纪元。
7.源Sentinel在接收到目标 Sentinel返回的命令回复之后,会检查回复中leader_epoch参数的值和自己的配置纪元是否相同,如果相同的话,那么源Sentinel继续取出回复中的leader runid参数,如果leader_runid参数的值和源Sentinel 的运行ID一致,那么表示目标Sentinel将源Sentinel设置成了局部领头Sentinel。
8.如果有某个Sentinel 被半数以上的Sentinel设置成了局部领头Sentinel,那么这个Sentinel成为领头Sentinel。举个例子,在一个由10个Sentinel组成的Sentinel系统里面,只要有大于等于10/2+1=6个Sentinel将某个Sentinel设置为局部领头Sentinel,那么被设置的那个Sentinel就会成为领头Sentinel。
9.因为领头Sentinel的产生需要半数以上Sentinel的支持,并且每个Sentinel在每个配置纪元里面只能设置一次局部领头Sentinel,所以在一个配置纪元里面,只会出现一个领头Sentinel。
10.如果在给定时限内,没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将在一段时间之后再次进行选举,直到选出领头Sentinel为止。
故障转移
在选举产生出领头Sentinel之后,领头Sentinel将对已下线的主服务器执行故障转移操作,该操作包含以下三个步骤∶
1)在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器,并将其转换为主服务器。
2)让已下线主服务器属下的所有从服务器改为复制新的主服务器。
3)将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,它就会成为新的主服务器的从服务器。
选出新的主服务器
故障转移操作第一步要做的就是在已下线主服务器属下的所有从服务器中,挑选出一个状态良好、数据完整的从服务器,然后向这个从服务器发送SLAVEOFno one命令,将这个从服务器转换为主服务器。
问题:新的主服务器是如何选出来的??
领头Sentinel会将已下线主服务器的所有从服务器保存到一个列表里面,然后按照以下规则,一项一项地对列表进行过滤∶
1)删除列表中所有处于下线或者断线状态的从服务器,这可以保证列表中剩余的从服务器都是正常在线的。
2)删除列表中所有最近五秒内没有回复过领头Sentinel的INFO命令的从服务器,这可以保证列表中剩余的从服务器都是最近成功进行过通信的。
3)删除所有与已下线主服务器连接断开超过down-after-milliseconds * 10 毫秒的从服务器∶down-after-milliseconds选项指定了判断主服务器下线所需的时间,而删除断开时长超过down-after-milliseconds * 10毫秒的从服务器,则可以保证列表中剩余的从服务器都没有过早地与主服务器断开连接,换句话说,列表中剩余的从服务器保存的数据都是比较新的。
之后,领头Sentinel将根据从服务器的优先级,对列表中剩余的从服务器进行排序,并选出其中优先级最高的从服务器。
如果有多个具有相同最高优先级的从服务器,那么领头Sentinel将按照从服务器的复制偏移量,对具有相同最高优先级的所有从服务器进行排序,并选出其中偏移量最大的从服务器(复制偏移量最大的从服务器就是保存着最新数据的从服务器)。最后,如果有多个优先级最高、复制偏移量最大的从服务器,那么领头Sentinel将按照运行ID对这些从服务器进行排序,并选出其中运行ID最小的从服务器。
修改从服务器的复制目标
当新的主服务器出现之后,领头Sentinel下一步要做的就是,让已下线主服务器属下的所有从服务器去复制新的主服务器,这一动作可以通过向从服务器发送SLAVEOF命令来实现。
image.png
image.png
将旧的主服务器变为从服务器
当server1重新上线时,Sentinel就会向它发送SLAVEOF命令,让它成为server2的从服务器。
网友评论