进阶的Redis之Sentinel原理及实战

Redis作为一款高效的内存数据库,可作用于方方面面,相信如今项目的开发都离不开它。大家可能都知道Redis是高可用的,但很少知道具体高可用是利用什么去实现的。

抛两个问题:

  1. 只部署一个Redis实例,如果这个实例挂了就无法读写数据了,那怎么做实例备份?
  2. 部署了两个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命令,让其成为新主库的从库。

    实验实战

  1. 启动三个Redis实例

    1
    2
    3
    redis-server --port 6379 &
    redis-server --port 6380 &
    redis-server --port 6381 &

    注意最好各个实例的priority不同,用于故障转移选主。否则可能会找不到新主。

  2. 把80与81的实例作为79的从服务器
    在80与81上执行

    1
    SLAVEOF 127.0.0.1 6379
  3. 启动sentinel

    1
    redis-sentinel /usr/local/etc/redis-sentinel.conf

    其中的Sentinel配置包含

    1
    sentinel monitor mymaster 127.0.0.1 6379 1

    可以观察到sentinel已经添加了一主两从的监控。

  4. 把主库的实例关掉

    1
    127.0.0.1:6379> SHUTDOWN
  5. 故障转移
    redis-cli连上sentinel可以看到,当sentinel检测到主库下线,后面根据一些列操作把81替换为主库,其他库为81的从库,并且79是下线的新从库。

参考文献:

  • 《Redis设计与实现》——黄健宏


    更多技术文章、精彩干货,请关注
    博客:zackku.com
    微信公众号:Zack说码

听说你想请我喝下午茶?~