在Redis主从复制的场景下,如果从库宕机,主库以及其它从库可以正常工作。但是主库挂掉后,虽然从库可以继续为客户端提供读请求,但是,却没有实例来继续完成读请求了。
主库挂掉后数据该往哪写?如何保证业务的可持续运行?
这儿就需要Redis的哨兵来解决了。
哨兵是一个独立的 Redis 进程,示例:
[root@iZ2zehs3cdd8rznk6ueeisZ ~]# ps aux | grep redis
redis 3040441 0.0 0.1 61984 4376 ? Ssl Nov11 3:21 /www/server/redis/src/redis-server 127.0.0.1:6379
root 3419825 0.0 0.3 61984 12832 pts/1 Sl+ 08:52 0:00 /www/server/redis/src/redis-sentinel *:26379 [sentinel]
root 3419889 0.0 0.0 12132 1144 pts/2 S+ 08:52 0:00 grep --color=auto redis
Sentinel(哨兵)
是用于监控 Redis 的主从实例,是 Redis 高可用的一个解决方案。当 Master 服务宕机后,能通过其余的 Slave 服务来选举出新的 Master 服务。解决了主从同步过程中主库宕机的问题。
哨兵主要的三个任务:监控、选主(选举新的主库)、通知。
监控是指哨兵在运行的过程中,周期性的给所有主从库发送 PING 命令,检测它们是否在线。
如果从库没有在规定时间响应哨兵的 PING 命令, 哨兵就会把它标记为 下线状态
。
同样,如果主库没有在规定时间相应哨兵的 PING 命令,哨兵就会判断主库下线,然后进行 自动切换主库
的流程。
这个流程是哨兵的第二个任务。
当主库挂掉后,哨兵会在多个从库中,按照一个规则选出一个新的主库。
通知是哨兵执行的最后一个任务。
哨兵会把新主库的连接信息发给其他从库,让它们执行 replicaof 命令,和新主库建立连接,并进行数据复制。同时,哨兵会把新主库的连接信息通知给客户端,让它们把请求操作发到新主库上。
哨兵的第一个任务就是监控,在监控的过程中有两个概念:主观下线和客观下线。
哨兵进程会使用 PING 命令检测它自己和主、从库的网络连接情况,用来判断实例的状态。如果哨兵发现主库或从库对 PING 命令的响应超时了,那么,哨兵就会先把它标记为 主观下线
。
如果检测的是从库,那么,哨兵简单地把它标记为 主观下线
就行了,因为从库的下线影响一般不太大,集群的对外服务不会间断。
但是如果检测的是主库,那么就不能简单的标记为客观下线了,因为在特殊的情况下哨兵会误判,导致进行主从切换,本来主库没问题的,一旦进行切换,会造成多余的计算及开销。
关于造成误判的原因:
如何避免这个问题呢?那就需要标记为客观下线了。
客观下线是所有哨兵一起判断,多数人认为主库下线了,才算真下线,才能进行后续切换。
引入多个哨兵实例一起来判断,就可以避免单个哨兵因为自身网络状况不好,而误判主库下线的情况。同时,多个哨兵的网络同时不稳定的概率较小,由它们一起做决策,误判率也能降低。
多数服从少数,当有 N 个哨兵实例时,最好要有 N/2 + 1
个实例判断主库为 主观下线
,才能最终判定主库为 客观下线
。
选主的时候,主要过程是:筛选 + 打分
。
先筛选掉一部分不符合规则的从库,在对剩下的从库进行打分,得分高者将成为主库。
在筛选的过程中,不但要看当前从库的状态,如果从库当前的状态是连接状态,那么不能说明当前从库的状态就是好的。例如,选了这个当前正在连接状态的从库,但是以前的网络状态不好,导致它成为了主库后,很快就宕机了,这就不符合我们的预期了。
因此,除了判断当前实例的网络状态,还要要先进行判断之前的网络状态。
接下来就要给剩余的从库打分了。
用户可以通过 slave-priority
配置项,给不同的从库设置不同优先级。
在选主时,哨兵会给优先级高的从库打高分,如果有一个从库优先级最高,那么它就是新主库了。如果从库的优先级都一样,那么哨兵开始第二轮打分。
主从库同步时有个命令传播的过程。在这个过程中,主库会用 master_repl_offset 记录当前的最新写操作在 repl_backlog_buffer 中的位置,而从库会用 slave_repl_offset 这个值记录当前的复制进度。
此时,我们想要找的从库,它的 slave_repl_offset 需要最接近 master_repl_offset。如果在所有从库中,有从库的 slave_repl_offset 最接近 master_repl_offset,那么它的得分就最高,可以作为新主库。
就像下图所示,旧主库的 master_repl_offset 是 1000,从库 1、2 和 3 的 slave_repl_offset 分别是 950、990 和 900,那么,从库 2 就应该被选为新主库。
如果有两个从库的 slave_repl_offset 值大小是一样的(例如,从库 1 和从库 2 的 slave_repl_offset 值都是 990),我们就需要给它们进行第三轮打分了。
每个实例都会有一个 ID,这个 ID 就类似于这里的从库的编号。目前,Redis 在选主库时,有一个默认的规定:在优先级和复制进度都相同的情况下,ID 号最小的从库得分最高,会被选为新主库。
首先,先搞好主从同步,我搞了四台服务器,配置了一主三从。
关于 Redis 搭建主从同步:链接: Redis 搭建主从同步
修改四台服务器中的配置文件:sentinel.conf
(通常该文件和 redis.conf 同目录)
四台服务器中配置相同几乎一样,本示例只为了实现该效果,如果在生产环境中搭建,需要根据自己的业务需求来配置不同的参数项。
sentinel.conf
:
sentinel announce-ip 39.101.1.111 #很多人测试是用的一台服务器,多个不同端口的redis服务,我这边是多个服务器,因此要指定当前ip,不同服务器用不同的当前IP。
sentinel monitor mymaster 39.101.1.111 6379 2 # 指定主库IP地址以及端口
四台服务器的 sentinel.conf
编辑完后,各自启动:/www/server/redis/src/redis-sentinel sentinel.conf
Redis 哨兵是为了解决 Redis 主从同步的时候宕机问题,是 Redis一种高可用的实现方案。
但是哨兵也会宕机,这时候又需要 Redis集群来解决了……
参考文档:https://time.geekbang.org/column/article/274483