【Redis技术探索】帮你完全搞定Sentinel(哨兵)原理
  TEZNKK3IfmPf 2023年11月13日 15 0

每日一句

最美好的生活方式是和一群志同道合的人,一起奔跑在理想的路上,回头有一路的故事,低头有坚定的脚步,抬头有清晰的远方!


Sentinel存在的意义

Sentinel出现的前提背景

在前面Redis技术系列的章节中,我们介绍了相关Redis持久化机制和Redis主从架构的探究。两者的相辅相成实现了Redis的数据高可用性以及服务的可扩展性和负载性,但是只依靠持久化方案和主从复制能力(负载和数据的荣誉),在出现服务宕机的时候,故障切换无法自动去实现,还需要手工,这对人工成本造成了巨大的损失以及不稳定性。

持久化+主从复制后的仍存在的痛点

主服务器下线后无法恢复服务使用主从复制,在master节点下线后,只能够手动将 slave 节点切换为 master,但是不能自动完成故障转移。

Sentinel的加入才够完整

Sentinel(哨兵)是Redis的高可用性解决方案:由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器

主从持久化机制与加入哨兵之后的对比:

【Redis技术探索】帮你完全搞定Sentinel(哨兵)原理


Sentinel的主要功能

Redis Sentinel为Redis提供了完整的高可用解决方案。实际上这意味着使用Sentinel可以部署一套Redis,在没有人为干预的情况下去应付各种各样的失败事件。同时提供了一些其他的功能,例如:监控、通知、并为client提供配置

Sentinel的概念定义

Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案 ,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。

Redis从 2.8发布了一个稳定版本的Redis Sentinel 。当前版本的 Sentinel称为Sentinel 2。它是使用更强大和更简单的预测算法来重写初始Sentinel实现。(Redis2.6版本提供Sentinel 1版本,但是有 一些问题)。


Sentinel的功能分布

  • 监控(Monitoring)Sentinel会不断的检查你的主节点和从节点是否正常工作

  • 通知(Notification):被监控的Redis实例如果出现问题,Sentinel可以通过API(pub)通知系统管理员或者其他程序。

  • 自动故障转移(Automatic failover):如果一个主节点没有按照预期工作,Sentinel 会开始进行故障转移,把一个从节点提升为主节点,并重新配置其他的从节点使用新的主节点,其他的从节点会开始复制新的主节点,并且使用Redis服务的应用程序在连接的时候也被通知新的地址。

  • 配置提供(Configuration provider):客户端可以把 Sentinel 作为权威的配置发布者来获得最新的maste 地址。如果发生了故障转移,Sentinel集群会通知客户端新的master地址,并刷新 Redis 的配置。(sentinel会返回最新的master地址)

Sentinel的分布特性

【Redis技术探索】帮你完全搞定Sentinel(哨兵)原理

  • 如果只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel本身也有单点问题,single-point-of-failure)整个集群系统将无法按照预期的方式运行。所以有必要将sentinel集群。

  • Redis Sentinel是一个分布式系统,Sentinel运行在有许多Sentinel进程互相合作的环境下,它本身就是这样被设计的。有许多Sentinel进程互相合作的优点如下:

    1. 当多个Sentinel同意一个master不再可用的时候,就执行故障检测。这明显降低了错误概率

    2. **即使并非全部的Sentinel都在工作,Sentinel也可以正常工作,这种特性,让系统非常的健康(最好是奇数个,因为不容易选举成为同票)**。

分布方式总体深入下图所示

【Redis技术探索】帮你完全搞定Sentinel(哨兵)原理

Sentinel的基本原理

总体而言:多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来 接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

Sentinel的主观下线(SDOWN)

一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线。

  • **在Sentinel哨兵的运行阶段,(其会向其他的Sentinel哨兵、master和slave发送消息确认其是否存活),如果在指定的时间内未收到正常回应,暂时认为对方挂起了(被标记为主观宕机–SDOWN)**。

    • 【**注意:当只有单个sentinel实例对redis实例做出无响应的判断,此时进入主观判断,不会触发自动故障转移等操作。**】
    • 注意:一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线

Sentinel的客观下线(ODOWN)

  • **当多个Sentinel哨兵(数量由quorum参数设定)都报告同一个master没有响应了,通过投票算法(Raft算法),系统判断其已死亡(被标记为客观宕机–ODOWN)**。

    • 多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断
    • Sentinel可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线

Sentinel下线操作

  • 从主观下线状态切换到客观下线状态并没有使用严格的法定人数算法(strong quorum algorithm), 而是使用了流言协议: 如果 Sentinel 在给定的时间范围内(master_down_after_milliseconds), 从其他 Sentinel 那里接收到了足够数量的主服务器下线报告, 那么 Sentinel 就会将主服务器的状态从主观下线改变为客观下线如果之后其他 Sentinel 不再报告主服务器已下线, 那么客观下线状态就会被移除。

  • 客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例(其他sentinel和slave服务节点), Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器Slave或者其他 Sentinel 永远不会达到客观下线条件

Sentinel的主从切换

  • 此时Sentinel集群会选取领头的哨兵(leader)进行故障恢复,从现有slave节点中选出(算法后续有介绍)一个提升为Master,并把剩余Slave都指向新的Master,继续维护主从关系

Sentinel自动发现机制

  • 那么,Sentinel集群的机器是如何发现集群中的其他机器呢?

    • 使用广播?很显然不合适,既然是redis的产品,自然要充分运用redis功能,Sentinel集群节点利用了Redis master的发布/订阅机制去自动发现其它节点

每个Sentinel使用发布/订阅的方式持续地传播master的配置版本信息,配置传播的发布/订阅管道是: sentinel:hello,我们可以通过订阅其频道查看频道中的消息,如下:

【Redis技术探索】帮你完全搞定Sentinel(哨兵)原理

Sentinel 利用 pub/sub(发布/订阅):

订阅了每个 master 和 slave 数据节点的 sentinel:hello 频道,去自动发现其它也监控了统一 master 的 sentinel 节点,Sentinel 向每 1s 向 sentinel:hello 中发送一条消息,包含了其当前维护的最新的master 配置。

【Redis技术探索】帮你完全搞定Sentinel(哨兵)原理

  • 如果某个sentinel发现自己的配置版本低于接收到的配置版本,则会用新的配置更新自己的 master 配置与发现的 Sentinel 之间相互建立命令连接之后会通过这个命令连接来交换对于 master 数据节点的看法

  • sentinel的状态会被持久化地写入sentinel的配置文件中。每次当收到一个新的配置时,或者新创建一个配置时,配置会被持久化到硬盘中,并带上配置的版本戳。这意味着,可以安全的停止和重启sentinel进程。

Sentinel的发现方式

原理中提及到了,当sentinel发现主库客观下线时候会进行领头哨兵选举超过半数切大于阈值)进行故障恢复,其选举算法采用Raft算法,这也为什么说其设计思想类似与zookpeer,选举过程大体如下:

  • **发现主库客观下线的哨兵节点(这里称为A)向每个哨兵节点发送命令要求对方选举自己为领头哨兵(leader)**;

  • 如果目标哨兵没有选举过其他人,则同意将A选举为领头哨兵

  • 如果A发现有超过半数且超过quorum参数值的哨兵节点同意选自己成为领头哨兵,则A哨兵成功选举为领头哨兵

    • sentinel集群执行故障转移时需要选举leader,此时涉及到majority,majority 代表 sentinel 集群中大部分 sentinel 节点的个数,只有大于等于 max(quorum, majority) 个节点给某个 sentinel 节点投票,才能确定该sentinel节点为leader,majority 的计算方式为:num(sentinels) / 2 + 1
  • 当有多个哨兵节点同时参与领头哨兵选举时,出现没有任何节点当选可能,此时每个参选节点等待一个随机时间进行下一轮选举,直到选出领头哨兵

故障恢复时从Slave中间选出Master的算法

  • 按照slave优先级进行排序slave-priority越低,优先级就越高

  • 如果slave priority相同,那么比较复制偏移量,offset越靠后(越大)则表明和旧的主库数据同步越接近,优先级就越高

  • 如果上面两个条件都相同,那么选择一个run id最小的从库

主要根据slave-priority进行排序做控制选举,先比较slave_offset值越大优先级越高,如果相等在获取runid最小的(代表启动时间越早)。

Sentinel(哨兵)的运作流程

  1. 每个Sentinel以每秒钟一次的频率向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令。(心跳机制)

  2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线

  3. 如果一个Master被标记为主观下线,则正在监视这个Master的所有 Sentinel 要以每秒一次的频率确认Master的确进入了主观下线状态。(确认投票下线

  4. 当有足够数量的 Sentinel(大于等于配置文件指定的值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线

  5. 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有Master,Slave发送 INFO 命令。(同步数据)

  6. 当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次

  7. 若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除

  8. 若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除


Sentinel部署配置

  • redis源码中提供了 sentinel 配置的模板:sentinel.conf

  • Sentinel部署很简单,只需要配置一下/etc/redis-sentinel.conf配置文件就可以了,如下

#工作端口
port 26379

#工作目录
dir "/var/lib/redis/sentinel"

#sentinel id ,建议注释掉,会自动生成
#sentinel myid 827f0104ad153f34db5a29b8cbb51ef21a31d6d5

#配置要监控的master名字和地址,最后一个2代表当sentinel集群中有2个sentinel认为master故障时候才判定master真正不可用。
官方把该参数称为quorum,在后续选举领头哨兵时候会用到
sentinel monitor mymaster 10.130.2.155 6379 2

#配置master密码:配置主服务器的密码(如没设置密码,可以省略)  
sentinel auth-pass mymaster Password

#日志
logfile "/var/log/redis/sentinel.log"
配置完成后,使用systemctl start redis-sentinel启动即可。


Sentinel可以调整的相关参数

#主观SDOWN时间,单位毫秒,默认30秒。(心跳检测)
sentinel down-after-milliseconds mymaster 30000

#在发生failover主备切换时候,最多允许多少个slave同时同步新的master。这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave处于不能处理命令请求的状态。

sentinel parallel-syncs mymaster 1

#failover-time超时时间,当failover开始后,在此时间内仍然没有触发任何failover操作,当前sentinel将会认为此次failover失败,单位毫秒。默认3分钟。
sentinel failover-timeout mymaster 180000

核心配置

sentinel monitor <master-name> <ip> <redis-port> <quorum>: 监控的 redis 主节点

#配置主服务器的密码(如没设置密码,可以省略) 
sentinel auth-pass mymaster 123456  

#修改心跳检测 5000毫秒
sentinel down-after-milliseconds mymaster 5000
  • sentinel 是 redis 配置的提供者,而不是代理,客户端只是从 sentinel 获取数据节点的配置,因此这里的 ip 必须是 redis 客户端能够访问的。

Sentinel 启动

虽然哨兵(sentinel) 释出为一个单独的可执行文件 redis-sentinel ,但实际上它只是一个运行在特殊模式下的 Redis 服务器,你可以在启动一个普通 Redis 服务器时通过给定 --sentinel 选项来启动哨兵(sentinel)。

如果你使用redis-sentinel可执行文件,你可以使用下面的命令来运行Sentinel:

$ redis-sentinel /path/to/sentinel.conf

当然也可以采用 redis服务的方式启动:

$ redis-server sentinel.conf --sentinel &

两种方式是一样的。

不管咋样,使用一个配置文件来运行Sentinel是必须的,这个文件被系统使用来存储当前状态,如果重启,这些状态会被重新载入。如果没有配置文件或者配置文件的路径不对,Sentinel将会拒绝启动。

默认情况下,Sentinels监听TCP端口26379,所以为了让Sentinels运行,你的机器的26379端口必须是打开的,用来接收其他Sentinel实例的连接,否则,Sentinels不能互相交流,也不知道该干什么,也不会执行故障转移。

1. 初始化一个普通的redis服务器

2. 加载Sentinel专用配置,例如命令表、参数等,Sentinel 使用 sentinel.c 中的命令表、函数等配置,普通 Redis 则使用 redis.c 中的配置

3. 除了保存服务器一般状态之外,Sentinel 还会保存 Sentinel 相关状态
注意:

1 .当启动哨兵模式之后,如果你的master服务器宕机之后,哨兵自动会在从redis服务器里面 投票选举一个master主服务器出来;这个主服务器也可以进行读写操作!

  1. 如果之前宕机的主服务器已经修好,可以正式运行了。那么这个服务器只能进行读的操作,会自动跟随由哨兵选举出来的新服务器!

  2. 大家可以进入./redis-cli,输入info,查看你的状态信息

【Redis技术探索】帮你完全搞定Sentinel(哨兵)原理

Redis截止到现在仍存在的问题

  • [哨兵已解决] :一旦主节点宕机,从节点晋升成主节点,同时需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预

  • [集群已解决] :节点的写能力受到单机的限制

  • [集群已解决] :节点的存储能力受到单机的限制

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   29天前   25   0   0 dataredis
  TEZNKK3IfmPf   29天前   21   0   0 awkredis
  TEZNKK3IfmPf   2024年04月19日   35   0   0 javarediskey
TEZNKK3IfmPf