Sentinel(哨岗,哨兵),是Redis的高可用解决方案:
- 由一个或多个Sentinel实例组成的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文件
使用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必须专门用一个专门连接 接收频道信息
获取主服务器信息
sentinel 默认每十秒,向被监视的主库发送一次INFO命令
并通过分析INFO命令的回复来获取主库的当前信息。
主库回复INFO命令,内容
- 主库本身信息
-
- run_id,role域记录的服务器角色
- 主库下面所有从库信息
-
- slave的id,ip,port,state,offset,lag 等等信息。
sentinel 将主信息存在master字典中,将从信息存在Slave字典中;
获取新增从库信息
当sentinel 发现主库有新从库出现时,会为这个新从库创建相应的实例结构
并创建连接到从库,命令连接和订阅连接。
这样sentinel,也会每个10秒 给从库发送INFO,命令并解析其返回的内容。
也就是说无论主库还是从库,sentinel都会定期去取他们的信息,来分析,并做动作。
sentinel与主从间的通信
对于监视同一个服务器的多个sentinel来说,一个sentinel发送的信息会被其他sentinel接收到
,这些信息会被用于更新其他sentinel。
三个监视器共同监视同一主服务器
使用命令连接相连的各个sentinel 可以通过向其他sentinel发送命令请求来进行信息交换。
检测主观下线状态
默认情况下,sentinel 会以每秒一次的频率向所有与他创建了命令连接的实例
包含 主库,从库,其他sentinel 在内 发送ping 命令,并通过实例返回的ping命令回复 来判断实例是否在线。
sentinel 向实例发送ping 命令。
有效回复:
- +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将对已下线的主库执行故障转移
- 在所有从库中,选出一个从库作为新的主库
- 将所有剩下的从库改为复制新的主库
- 将源主库设置为新的主库的从库
- 这个源主库重新上线时,它会成为新主库的从库
选出新的主库
挑选一个状态良好,数据完整的从库,然后这个从库,执行
slaveof no one
将从库转变为主库。
新主库如何挑选规则
- 删除所有处于下线或断线的从库,保证剩余从库都是正常在线
- 删除最近5秒没有回复过领头sentinel的INFO命令的从库
- 保证剩余从库都是最近成功通信过的
- 删除所有与源主库连接断开超过 down-after-milliseconds*10 的从库
- 保证剩余从库保存的数据都是较新的
- 领头sentinel根据从库的优先级,进行排序,选择优先级最高的从库
总结
- sentinel 是一个特殊模式下的redis服务器。
- 使用了不同的命令表;
- sentinel 读取配置文件
- 为每个主库创建实例结构,并创建连接
- sentinel 默认每十秒 发送INFO命令 检测服务器是否在线
- 对于监视同一服务器的多个sentinel,它们会每两秒一次,通过被监视的服务器的频道
- __sentinel__:hello 频道发送消息,向其他sentinel宣告自己的存在
- 多个sentinel 之间也会创建连接,用于传送命令
- sentinel只会与主服务器和从服务器来创建命令连接和订阅连接
- sentinel 与 sentinel 之间只创建命令连接
- sentinel 默认每秒向实例(包括主库,从库,其他sentinel)发送ping 命令,
- 根据实例对返回,判断实例是否在线
- 当实例在指定时间内连续回复无效信息,则主库将判断为主观下线
- 当sentinel 判断一个主库为主观下线,他会向其他sentinel 询问,看它们是否同意这个主库进入主观下线状态
- 当sentinel收到足够多的主观下线投票之后,它会将主服务器判断为客观下线。