Sentinel(哨岗,哨兵),是Redis的高可用解决方案:


  • 由一个或多个Sentinel实例组成的Sentinel系统,
  • 可以监视任意多个主服务器,以及这些主库下面的从库
  • 并在主库掉线之后,自动选择某个从库作为新的主库。

 


说到底,就是探活,主从切换==高可用



 

RedissonClient 是哪个依赖 redis-sentinel_服务器

 



启动并初始化Sentinel



redis-sentinel /path/to/your/sentinel.conf



redis-server /path/to/your/sentinel.conf --sentinel


当启动一个sentinel时,它需要执行以下步骤



  • 初始化服务器
  • 将普通Redis服务器使用的代码替换成Sentinel 专用代码
  • 初始化Sentinel状态
  • 根据给定的配置文件,初始化Sentinel的监控主服务器列表
  • 创建连向主服务器的网络连接

 


初始化服务器

sentinel 实际上是redis的一种特殊形式,因此大体初始化和redis初始化相似


不同点


  • 普通服务器初始化时会载入RDB文件或AOF文件来还原数据库状态
  • sentinel 并不使用数据库,初始化Sentinel时不会载入RDB文件或AOF文件



RedissonClient 是哪个依赖 redis-sentinel_数据库_02

 



使用sentinel专用代码

不同点


  • 端口号
  • redis常用端口号         6379
  • sentinel常用端口号    26379
  • 命令表
  • redis--redisCommandTable
  • 如 set,get,script 等等键值对命令
  • sentinel --sentinelcmds
  • 仅包含7个命令
  • ping,sentinel,info,
  • subscribe,unsubscribe,psubscribe,punsubscribe

 



初始化sentinel状态的masters属性

sentinel状态中masters字典记录了所有被Sentinel监视的主服务器的相关信息;



  • 字典的键是被监视主服务器的名字
  • 字典的值则是被监视主服务器对应的 结构
  • 实例结构的属性有很多

 

创建连向主服务器的网络连接


创建连向被监视主服务器的网络连接,Sentinel将成为主服务器的客户端,它可以向主服务器发送命令,并从命名回复中获取相关信息。


对于每个被sentinel监视的主服务器来说,sentinel会创建两个连向主服务器的异步网络连接:



  • 命令连接
  • 专门用于向主库发送命令,接收命令回复。
  • 订阅连接
  • 专门用于订阅主库的__sentinel__:hello频道


为啥又两个连接?


  • 在Redis目前的发布与订阅功能中,被发送的信息都不会保存在redis服务器里面。
  • 如果在发送信息时,想要接收信息的客户端不在线或者断线,那么这个客户端就会丢失这条信息。
  • 因此,为了不丢失__sentinel__:hello 频道的任何信息,Sentinel必须专门用一个专门连接 接收频道信息



RedissonClient 是哪个依赖 redis-sentinel_数据库_03

 




获取主服务器信息



sentinel 默认每十秒,向被监视的主库发送一次INFO命令



并通过分析INFO命令的回复来获取主库的当前信息。




 

RedissonClient 是哪个依赖 redis-sentinel_初始化_04

 



主库回复INFO命令,内容



  • 主库本身信息
  • run_id,role域记录的服务器角色
  • 主库下面所有从库信息
  • slave的id,ip,port,state,offset,lag 等等信息。

 

sentinel 将主信息存在master字典中,将从信息存在Slave字典中;


获取新增从库信息


 

当sentinel 发现主库有新从库出现时,会为这个新从库创建相应的实例结构



并创建连接到从库,命令连接和订阅连接。



 

RedissonClient 是哪个依赖 redis-sentinel_初始化_05

 


这样sentinel,也会每个10秒 给从库发送INFO,命令并解析其返回的内容。

也就是说无论主库还是从库,sentinel都会定期去取他们的信息,来分析,并做动作。

sentinel与主从间的通信





RedissonClient 是哪个依赖 redis-sentinel_数据库_06


对于监视同一个服务器的多个sentinel来说,一个sentinel发送的信息会被其他sentinel接收到


,这些信息会被用于更新其他sentinel。


 


 

RedissonClient 是哪个依赖 redis-sentinel_初始化_07


三个监视器共同监视同一主服务器


RedissonClient 是哪个依赖 redis-sentinel_服务器_08

 


使用命令连接相连的各个sentinel 可以通过向其他sentinel发送命令请求来进行信息交换。


 


检测主观下线状态



默认情况下,sentinel 会以每秒一次的频率向所有与他创建了命令连接的实例


包含 主库,从库,其他sentinel 在内 发送ping 命令,并通过实例返回的ping命令回复 来判断实例是否在线。

sentinel 向实例发送ping 命令。


RedissonClient 是哪个依赖 redis-sentinel_redis_09

 


有效回复:


  • +PONG,-LOADING,-MASTERRDOWN

 

如果ping 命令 没有 得到上面的有效回复 则 主观下线 实例


或者是 在 down-after-milliseconds 后还没收到任何回复 也选择主观下线。


检查客观下线状态



  • 当sentinel 将一个主服务器判断为 主观下线之后,为了确认是否真的下线了。
  • 它会向同样监视着以主服务器的其他sentinel 进行询问,
  • 看它们是否也认为主服务器已经进入下线状态(可以是主观下线或客观下线)。当sentinel 从其他
  • sentinel 接收到足够数量的已下线判断后,sentinel 就会将主服务器判定为客观下线,并执行故障转移操作

 


使用命令,判断主库是否真下线


sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>

current_epoch: sentinel 当前的配置纪元,用于选举领头sentinel;

当其他sentinel接收到 is-master-down-by-addr 后返回 三个参数


  • <down_state>
  • 1 主库已下线,0 主库未下线
  • <leader_runid>
  • 仅用于检测主库下线的标志
  • 局部领头sentinel 的运行ID
  • 用于选举领头sentinel ID
  • <leader_epoch>
  • 局部领头sentinel 的配置纪元
  • 用于选举领头sentinel
  • 仅在<leader_runid>不为* 时有效,为* 时,其值始终为0

 

选举领头sentinel



  • 当主库被判断为客观下线时,监视这个主库的各个sentinel 会进行协商,
  • 选出一个领头sentinel,并由其来执行对下线主库的故障转移

 

Redis 选举领头Sentinel 的规则


  • 所有在线Sentinel 都有被选为领头Sentinel的资格
  • 每次进行领头Sentinel选举后,无论是否成功,所有sentinel 的配置纪元(configuration epoch) 自增一次
  • 配置纪元实际就是一个计数器,没有特殊作用
  • 所有sentinel 只能选择一个 sentinel 作为领头,并且局部领头 sentinel 一旦设置,在这个配置纪元就不能修改

 


方法


  • 每个发现主库进行客观下线的sentinel都会要求设置它自己为领头
  • 当发送命令中runid 不是* 而是源sentinel 本身的 id,
  • 则要求其他sentinel将其本身设置为领头
  • 目标sentinel设置领头 规则是先到先得
  • sentinel一旦设置某为领头,则其余的要求都会被拒绝
  • 设置的方法,就是命令的回复
  • leader_runid 和 leader_epoch
  • 源sentinel接收到回复之后
  • 检查回复中的leader_epoch,leader_runid 是否 符合本身的current_epoch ,runid
  • 如相同则表示 其已被设置为领头
  • 如某个Sentinel 被半数以上的Sentinel 设置为局部领头,那么此Sentinel 成为领头Sentinel。
  • 因领头Sentinel 需要得到半数以上的支持,且每个Sentinel在每个配置纪元中,只有一次投票权
  • 所以 在每个配置纪元中,只会出现一个领头Sentinel。
  • 如果在规定时间内,没有选出领头,则各个Sentinel将在一段时间后再次选举,直到选出领头Sentinel为止。

 


故障转移



领头sentinel将对已下线的主库执行故障转移


  1. 在所有从库中,选出一个从库作为新的主库
  2. 将所有剩下的从库改为复制新的主库
  3. 将源主库设置为新的主库的从库
  • 这个源主库重新上线时,它会成为新主库的从库

 


选出新的主库


挑选一个状态良好,数据完整的从库,然后这个从库,执行


slaveof no one 


将从库转变为主库。

新主库如何挑选规则


  1. 删除所有处于下线或断线的从库,保证剩余从库都是正常在线
  2. 删除最近5秒没有回复过领头sentinel的INFO命令的从库
  • 保证剩余从库都是最近成功通信过的
  1. 删除所有与源主库连接断开超过 down-after-milliseconds*10 的从库
  • 保证剩余从库保存的数据都是较新的
  1. 领头sentinel根据从库的优先级,进行排序,选择优先级最高的从库

 

RedissonClient 是哪个依赖 redis-sentinel_redis_10

RedissonClient 是哪个依赖 redis-sentinel_数据库_11

 

RedissonClient 是哪个依赖 redis-sentinel_数据库_12

 

 

总结



  • sentinel 是一个特殊模式下的redis服务器。
  • 使用了不同的命令表;
  • sentinel 读取配置文件
  • 为每个主库创建实例结构,并创建连接
  • sentinel 默认每十秒 发送INFO命令 检测服务器是否在线 
  • 对于监视同一服务器的多个sentinel,它们会每两秒一次,通过被监视的服务器的频道
  • __sentinel__:hello 频道发送消息,向其他sentinel宣告自己的存在
  • 多个sentinel 之间也会创建连接,用于传送命令
  • sentinel只会与主服务器和从服务器来创建命令连接和订阅连接
  • sentinel 与 sentinel 之间只创建命令连接
  • sentinel 默认每秒向实例(包括主库,从库,其他sentinel)发送ping 命令,
  • 根据实例对返回,判断实例是否在线
  • 当实例在指定时间内连续回复无效信息,则主库将判断为主观下线
  • 当sentinel 判断一个主库为主观下线,他会向其他sentinel 询问,看它们是否同意这个主库进入主观下线状态
  • 当sentinel收到足够多的主观下线投票之后,它会将主服务器判断为客观下线。