一、Redis的哨兵机制
在主从模式下,如果主库挂了,从库虽然可以继续接受客户端的读请求,但是这个时候客户端发送写请求,这个时候就没有服务来接受写请求了,有什么办法吗?本章介绍一下 哨兵机制。
哨兵是建立在主从模式基础之上。
主库正常:
主库挂了
哨兵机制在Redis集群中,实现了自动主从切换机制。
哨兵机制的基本流程
哨兵机制主要负责三个任务:监控,选主、通知从库。
- 监控:是指哨兵进程在运行的同时,周期性的向所有的主从库发送 ping命令,检查他们是否正常在线运行,如果从库没有在规定时间内响应哨兵的 ping命令,哨兵就会把它标记为 “下线状态”,如果主库没有在规定时间内响应哨兵的 ping命令, 哨兵就会判定主库下线,然后开始自动 切换主库 的流程 。
- 选主:主库在挂了之后,哨兵就在多个从库中,按照一定的规则把一个从库选择为主库,这样,redis集群中就有了新的主库。
- 通知:在执行任务通知时,哨兵会把选择出来的新主库的信息发送给其他的从库,让他们执行 replicaof 命令,和主库建立新的连接,并进行数据复制,并把新的主库信息同步给客户端,让写请求发送到新的主库上面。
哨兵机制的3个任务及目标:
两个决策
- 在监控任务中,哨兵需要判断主库是否是下线状态。
- 在选主任务中,哨兵也需要判断哪个从库可以作为主库。
主观下线和客观下线
主观下线
- 哨兵进程会使用 ping 命令检测它自己和主、从库的网络状态,用它来判断实际的情况,如果发现主库或者从库对ping的命令超时了,那么哨兵会把它先标记为 “主观下线”。
- 如果是从库,哨兵会把它标记为 “主观下线”就行了,因为从库的影响不太大,集群对外的服务不会挂断。
- 但是如果检测的是主库,哨兵不会简单就把它标记为 “主观下线”,开启主从切换,因为可能存在一个情况,哨兵误判了,其实主库没有主从故障,一旦进行主从切换,后续的选主和通知操作就会带来额外的计算和开销。
误判一般会发生在集群网络压力较大,网络拥堵、或者是主库压力比较大的情况下。
一旦哨兵判断主库下线了,就会开始选择新主库,并让从库和新主库进行数据同步,这个过程本身就会有开销,例如,哨兵要花时间选出新主库,从库也需要花时间和新主库同步。而在误判的情况下,主库本身根本就不需要进行切换的,所以这个过程的开销是没有价值的。正因为这样,我们需要判断是否有误判,以及减少误判。
如何减少误判
通过哨兵集群,引入多个哨兵一起来判断,可以避免单个哨兵自身网络不好的情况,而误判主库下线的情况,误判率可以减低。
在判断主库下线时,不能由一个哨兵说了算,只有大多数的哨兵实列,都判断主库已经 “主观下线了”,主库才会被标记为 “客观下线”,
判断上线状态
判断客观下线
客观下线的标准就是当有 N 个哨兵实列,当 (n/2)+1实列判断为主观下线,最终就会判断主库为 “客观下线”。
如何选主库
筛选
在redis配置中,有一个 down-after-milliseconds 参数,这个参数表示主库断连的最大时间,如果配置为 down-after-milliseconds * 10,如果发生了10次断连,那么就证明这个从库的网络状态不好,不适合作为新的主库。
打分
打分规则依次为:从库优先级 -> 从库复制进度 -> 从库 ID号,主要在某一轮那个从库得分最高,那么它就是新的主库了。
- 从库优先级:通过 slave-priority配置项,可以手动给从库分配不同的优先级,在选主时,优先通过这个选项最高者,就是新的从库了。
- 从库复制进度:在学习主从原理机制的时候,我们知道有一个 repl_backlog_buffer 来记录主从同步的 offset,主库会用 master_repl_offset,而从库使用 slave_repl_offset 。此时哪一个的 slave_repl_offset 接近 master_repl_offset,那么它就是新的从库了。
- 从库ID号:目前,在redis选主的过程中,默认规定:在优先级和复制进度相同的情况下, id号最小的从库会优先选择为主库。
二、Windows下搭建Redis哨兵集群
这里我们使用一个主节点(主)和一个子节点(从)。
从节点使用哨兵模式进行监控,如果主库挂了,从库自动升级为主节点,等待主库恢复了,主库会自动变为从库。
但此时,如果升级为主库的从节点挂了,此时变为从库的主节点不会变为主库,出现这种问题,我们一般采用的是主从都进行哨兵模式配置,互相监控对方,从而达到高可用。
redis 主 port 6380 Sentinel (哨兵端口)26380
redis 从 port 6381 Sentinel (哨兵端口)26381
-- redis下载解压完成后,复制4份,一份是主节点,一份是从节点,两份是哨兵。
由于windows版本的redis没有 Sentinel.conf文件 所以在redis的文件中创建一个。
主服务6380 哨兵监听 从节点6381。
# 当前Sentinel服务运行的端口
port 26380
#master
sentinel monitor master 127.0.0.1 6381 1
sentinel down-after-milliseconds master 5000
sentinel failover-timeout master 180000
sentinel parallel-syncs master 1
从节点6381 哨兵监听 主服务6380
port 26381
# Sentinel去监视一个名为mymaster的主redis实例,
# 这个主实例的IP地址为本机地址127.0.0.1,端口号为6379,
# 而将这个主实例判断为失效至少需要2个 Sentinel进程的同意,
# 只要同意Sentinel的数量不达标,自动failover就不会执行
# 这个一定设置为 no 或者这里不设置 需要在哨兵中关闭保护模式。
# protected-mode no
# 指定了Sentinel认为Redis实例已经失效所需的毫秒数。
# 当 实例超过该时间没有返回PING,或者直接返回错误,那么Sentinel将这个实例标记为主观下线。
# 只有一个 Sentinel进程将实例标记为主观下线并不一定会引起实例的自动故障迁移:只有在足够数量的Sentinel都将一个实例标记为主观下线之后,实例才会被标记为客观下线,这时自动故障迁移才会执行
sentinel monitor mymaster 127.0.0.1 6380 1
# 指定了在执行故障转移时,最多可以有多少个从Redis实例在同步新的主实例,在从Redis实例较多的情况下这个数字越小,同步的时间越长,完成故障转移所需的时间就越长
sentinel down-after-milliseconds mymaster 5000
# 如果在该时间(ms)内未能完成failover操作,则认为该failover失败
sentinel failover-timeout mymaster 10000
启动redis:
redis-server.exe redis.windows.conf
启动哨兵:
redis-server.exe sentinel.conf --sentinel
停止6380 主节点,查看从节点6381 可以看到升为主节点了,可以从6381哨兵中看到:
在启动6380 主节点 ,可以看到 6380主节点转为6380的从节点,可以在6380的哨兵中看到:
一主已从两哨兵的目的是:
- 主库挂了从升级为主库,原来主库恢复了之后成为从库
- 升级为主库的从库挂了之后,降为从库的主库再升级为主库
两者进行切换。
从 sentinel 日志中出现的几个消息来进行查看故障转移:
① +switch-master:表示切换主节点(从节点晋升为主节点)
② +sdown:主观下线
③ +odown:客观下线
④ +convert-to-slave:切换从节点(原主节点降为从节点)
哨兵模式可能发生的问题:
访问瞬断:在主节点宕机时,哨兵会发起选举。在选举过程中,如果客户端发起请求,会发生异常。当主节点重新选举出来,又会恢复。该问题在哨兵模式下无法避免。