Redis作为一款高效的内存数据库,可作用于方方面面,相信如今项目的开发都离不开它。大家可能都知道Redis是高可用的,但很少知道具体高可用是利用什么去实现的。
抛两个问题:
- 只部署一个Redis实例,如果这个实例挂了就无法读写数据了,那怎么做实例备份?
- 部署了两个Redis,一主一从做复制,从只读,如果主挂了,那这个服务还怎么正常对外服务?
显然,要做到高可用,首先要有足够多的Redis实例(最好三台以上),一主多从。然后再主挂了的时候,要有机制让其他实例替代主的位置。
哨兵服务Sentinel,就是这套题的答案,它是一个检查redis服务下线并补偿的服务。下面我们来完整了解下Sentinel的作用和工作原理,最后实验下它的效果。
Sentinel简介
直接看下最新版的官方的介绍
大致意思是,Sentinel为Redis提供高可用。利用Sentinel,在无人干预的情况下,可用让Redis服务抵御一定程度的故障。
宏观层面,Sentinel拥有以下几个功能:
- 监控(Monitoring),Sentinel可用持续不断地检查主从实例是否如期运行。
- 通知(Notification),当某个被监控的Redis实例出问题的时候,可以通过API接口向系统管理员和其他应用服务发通知。
- 自动故障转移(Automatic failover),当主出现故障时,Sentinel会自动启动故障转移流程,把其中一个从库提升为主库,然后其他从库重新认新主。集群也会返回新的地址给客户端。
- 配置提供(Configuration provider),Sentinel可以作为服务注册中心,让客户端直接连接请求Sentinel去获取主库的地址。如果出现自动故障转移,Sentinel也会提供新的主库地址。
P.S. 文中所描述的库和服务器都是指Redis的server实例。
高可用工作原理
下面我们以Sentinel的故障转移为核心,来看看它具体是怎么实现Sentinel的。
- 启动并初始化Sentinel
执行redis-sentinel /usr/local/etc/redis-sentinel.conf
Sentinel是Redis的特殊模式,执行redis-server /usr/local/etc/redis-sentinel.conf --sentinel
命令也是完全一样的。其实在启动Sentinel的时候,redis只是把运行代码切换到sentinel模式。 - 初始化master属性
配置文件中是需要指定了监控的主库,然后再初始化阶段把Sentinel实例中的master属性初始化。 - Sentinel向主库建立网络连接
在master属性初始化后,Sentinel首先就需要和该主库建立网络连接。Sentinel会对每个被监视的主库建立两个链接。一个命令链接,用于给主库发送操作命令的。另一个是订阅链接,订阅主库的__sentinel__:hello频道,主要用于发现其他Sentinel的存在(后面会说到)。 - 获取主库信息
Sentinel默认以十秒一次,通过命令链接,给主库发送INFO命令,来获取主库的当前信息。信息包括该主库的运行id以及该主库下所有从库的ip端口。 - 根据主库信息,获取从库信息
如果Sentinel在获取主库信息时候,发现有新未链接的从库,会与该从库同样建立两条链接。建立链接后,Sentinel同样会给从库通过命令链接发送INFO命令,从而获取该从库的服务器信息。 - 向主和从发送服务器消息
Sentinel默认以两秒一次,通过命令链接,对__sentinel__:hello频道发送Sentinel自身信息与被监控的主库信息。该频道是之前Sentinel与所有主从库都建立的频道链接。所以被监视的主从库都会收到发送消息的Sentinel信息与主库信息。 - 接收主从频道消息,找出其他Sentinel
因为Sentinel订阅了__sentinel__:hello的消息,所以在之前向主从库发送消息的时候,同时会通过订阅链接收到订阅的内容。这个作用在于,部署多个Sentinel时,其他Sentinel就会知道发送消息的那个Sentinel的存在。 - 与其他Sentinel创建连接
当Sentinel发现有其他Sentinel存在的时候,就会与其他Sentinel建立一条命令链接,用于在后续情况发送命令。但Sentinel之间不会建立订阅链接,因为订阅链接是用于发现其他Sentinel的存在的。 - 主观下线
Sentinel默认以一秒一次,通过命令链接,对所有服务器(包括主从、其他Sentinel)发送PING命令来检测服务是否在线。如果一个服务在参数down-after-millisecond
内连续返回无效回复,那么Sentinel会对该服务标记为主观下线状态。所谓的主观下线,就是Sentinel自己认为该服务下线了。 - 主库客观下线
当Sentinel将一个主库主观下线后,为了判断是否其他Sentinel都认为该主库下线了,会通过is-master-down-by-addr
命令询问。当认为下线的Sentinel数据大于配置中的quorum数时,Sentinel会标记该主库为客观下线。 - 选举Sentinel leader
当Sentinel将主库客观下线后,会与其他Sentinel进行协商,选举出一个leader来执行后续的Failover(故障转移)。 - 选出新主库。
leader按从库优先级配置、复制偏移量、运行id来选举出新的主库。leader会向挑选出来的从库发送SLAVEOF no one命令,将从库提升为master角色,成为主库。 - 让从库复制新主库
在选出新主库后,就是让原来的从库去复制新主库。leader Sentinel通过给剩余旧从库发送SLAVEOF命令即可。 - 旧主库变为新主库的从库
当原来故障的主库再次上线的时候,Sentinel会发送SLAVEOF命令,让其成为新主库的从库。实验实战
启动三个Redis实例
1
2
3redis-server --port 6379 &
redis-server --port 6380 &
redis-server --port 6381 &注意最好各个实例的priority不同,用于故障转移选主。否则可能会找不到新主。
把80与81的实例作为79的从服务器
在80与81上执行1
SLAVEOF 127.0.0.1 6379
启动sentinel
1
redis-sentinel /usr/local/etc/redis-sentinel.conf
其中的Sentinel配置包含
1
sentinel monitor mymaster 127.0.0.1 6379 1
可以观察到sentinel已经添加了一主两从的监控。
把主库的实例关掉
1
127.0.0.1:6379> SHUTDOWN
故障转移
redis-cli连上sentinel可以看到,当sentinel检测到主库下线,后面根据一些列操作把81替换为主库,其他库为81的从库,并且79是下线的新从库。
参考文献:
《Redis设计与实现》——黄健宏
更多技术文章、精彩干货,请关注
博客:zackku.com
微信公众号:Zack说码