写点什么

🚄【Redis 干货领域】帮你完全搞定 Sentinel 运作原理

发布于: 2021 年 05 月 21 日
🚄【Redis 干货领域】帮你完全搞定Sentinel运作原理

👮‍每日一句

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

👮‍ Sentinel 存在的意义

👮‍ Sentinel 出现的前提背景

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

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

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

👮‍ Sentinel 的加入才够完整

Sentinel(哨兵)是 Redis 的高可用性解决方案:由一个或多个 Sentinel 实例组成的 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 的分布特性



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

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

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

    即使并非全部的 Sentinel 都在工作,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,我们可以通过订阅其频道查看频道中的消息,如下:



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

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



  • 如果某个 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 仍存在的问题

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

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

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

发布于: 2021 年 05 月 21 日阅读数: 528
用户头像

我们始于迷惘,终于更高水平的迷惘。 2020.03.25 加入

🏆 【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 🤝未来我们希望可以共同进步🤝

评论

发布
暂无评论
🚄【Redis 干货领域】帮你完全搞定Sentinel运作原理