Redis 的 Sentinel 系统

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Sentinel 是 Redis 的高可用性解决方案:由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

介绍 Redis 的 Sentinel 系统

技术是为了解决问题而生的,Redis 的 Sentinel 系统实现了 Redis 主从服务器的自动切换。

Sentinel 是 Redis 的高可用性解决方案:由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

Sentinel 系统监视服务器的原理

Sentinel 和一般 Redis 服务器的区别:Sentinel 本质上只是一个运行在特殊模式下的 Redis 服务器。

Sentinel 会读入用户指定的配置文件,为每个要被监视的主服务器创建相应的实例结构,并创建连向主服务器的命令连接和订阅连接:

  • 命令连接用于,向主服务器发送命令请求;
  • 订阅连接用于,接收指定频道的消息。

Sentinel 通过向主服务器发送 info 命令来获得主服务器属下所有从服务器的地址信息,并为这些从服务器创建相应的实例结构,以及连向这些从服务器的命令连接和订阅连接。


在一般情况下,Sentinel 以每十秒一次的频率向被监视的主服务器和从服务器发送 info 命令。当主服务器处于下线状态,或者 Sentinel 正在对主服务器进行故障转移操作时,Sentinel 向从服务器发送 info 命令的频率会改为每秒一次。

对于监视同一个主服务器和从服务器的多个 Sentinel 来说,它们会以每两秒一次的频率,通过向被监视服务器的 __ sentinel __:hello 频道发送消息来向其他 Sentinel 宣告自己的存在。

每个 Sentinel 也会从 __ sentinel __:hello 频道中接收其他 Sentinel 发来的信息,并根据这些信息为其他 Sentinel 创建相应的实例结构,以及命令连接。

Sentinel 只会与主服务器和从服务器创建命令连接和订阅连接, Sentinel 与 Sentinel 之间则只创建命令连接。

Sentinel 系统对主服务器执行故障转移的整个过程

在默认情况下,Sentinel 会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他 Sentinel 在内)发送 ping 命令,并根据实例对 ping 命令的回复来判断实例是否在线,当一个实例在指定的时长中连续向 Sentinel 发送无效回复时,Sentinel 会将这个实例判断为主观下线。

当 Sentinel 将一个主服务器判断为主观下线时,它会向同样监视这个主服务器的其他 Sentinel 进行询问,看它们是否同意这个主服务器已经进入主观下线状态。当 Sentinel 收集到足够多的主观下线投票之后,它会将主服务器判断为客观下线。

当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个 Sentinel 会进行协商,选举出一个领头 Sentinel,并由领头 Sentinel 对下线主服务器执行故障转移操作。


在选举产生出领头 Sentinel 之后,领头 Sentinel 将对已下线的主服务器执行故障转移操作,该操作包含以下三个步骤:

  1. 选出新的主服务器:在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器,并将其转换为主服务器。
  2. 修改从服务器的复制目标:让已下线主服务器属下的所有从服务器改为复制新的主服务器。
  3. 将旧的主服务器变为从服务器:将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,它就会成为新的主服务器的从服务器。

1、检测服务器的下线状态

在默认情况下,Sentinel 会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他 Sentinel 在内)发送 ping 命令,并根据实例对 ping 命令的回复来判断实例是否在线,当一个实例在指定的时长中连续向 Sentinel 发送无效回复时,Sentinel 会将这个实例判断为主观下线。

当 Sentinel 将一个主服务器判断为主观下线时,它会向同样监视这个主服务器的其他 Sentinel 进行询问,看它们是否同意这个主服务器已经进入主观下线状态。

当 Sentinel 收集到足够多的主观下线投票之后,它会将主服务器判断为客观下线,并发起一次针对主服务器的故障转移操作。


实例对 ping 命令的回复可以分为以下两种情况:

  • 有效回复:实例返回 +pong、-loading、-masterdown 三种回复的其中一种。
  • 无效回复:实例返回除 +pong、-loading、-masterdown 三种回复之外的其他回复,或者在指定时限内没有返回任何回复。

1、检测主观下线状态

down-after-milliseconds 选项(主观下线时长 选项)

Sentinel 配置文件中的 down-after-milliseconds 选项指定了 Sentinel 判断实例进入主观下线所需的时间长度。

如果一个实例在 down-after-milliseconds 毫秒内,连续向 Sentinel 返回无效回复,那么 Sentinel 就会将该实例标记为主观下线。修改这个实例所对应的实例结构,在结构的 flags 属性中打开 SRI_S_DOWN 标识,以此来表示这个实例已经进入主观下线状态。


down-after-milliseconds 选项的作用范围

用户设置的 down-after-milliseconds 选项的值,不仅会被 Sentinel 用来判断主服务器的主观下线状态,还会被用于判断主服务器属下的所有从服务器,以及所有同样监视这个主服务器的其他 Sentinel 的主观下线状态。

2、检测客观下线状态

当 Sentinel 将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这个主服务器的其他 Sentinel 进行询问,看它们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。

当 Sentinel 从其他 Sentinel 那里接收到足够数量的已下线判断之后,Sentinel 就会将主服务器判定为客观下线,并对主服务器执行故障转移操作。

客观下线状态的判断条件:当认为主服务器已经进入下线状态的 Sentinel 的数量,超过 Sentinel 配置中设置的 quorum 参数的值,那么该 Sentinel 就会认为主服务器已经进入客观下线状态。


检测客观下线的具体流程:

源 Sentinel 发送命令:Sentinel 使用 sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid> 命令询问其他 Sentinel 是否同意主服务器已下线。

目标 Sentinel 接收命令:当一个 Sentinel(目标 Sentinel)接收到另一个 Sentinel(源 Sentinel) 发来的该命令时,目标 Sentinel 会分析并取出命令请求中包含的各个参数,并根据其中的主服务器 IP 和端口号,检查主服务器是否已下线,然后向源 Sentinel 返回一条包含三个参数的 MultiBulk 回复作为该命令的回复。

  • down_state:返回目标 Sentinel 对主服务器的检查结果,1 代表主服务器已下线,0 代表主服务器未下线
  • leader_runid:可以是 符号或者目标 Sentinel 的局部领头 Sentinel 的运行 ID。符号代表命令仅仅用于检测主服务器的下线状态,而局部领头 Sentinel 的运行 ID 则用于选举领头 Sentinel
  • leader_epoch:目标 Sentinel 的局部领头 Sentinel 的配置纪元,用于选举领头 Sentinel。仅在 leader_ runid 的值不为 时有效,如果 leader_ runid 的值为 ,那么 leader_ epoch 总为 0

源 Sentinel 接收命令的回复:根据其他 Sentinel 对该命令的回复,Sentinel 将统计其他 Sentinel 同意主服务器已下线的数量,当这一数量达到配置指定的判断客观下线所需的数量时,Sentinel 就会将该实例标记为客观下线。修改这个实例所对应的实例结构,在结构的 flags 属性中打开 SRI_O_DOWN 标识,以此来表示这个实例已经进入客观下线状态。


Redis 检测客观下线状态 / 选举领头 Sentinel 的命令:sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>

  • 参数 ip:被 Sentinel 判断为主观下线的主服务器的 IP 地址
  • 参数 port:被 Sentinel 判断为主观下线的主服务器的端口号
  • 参数 current_epoch:Sentinel 当前的配置纪元,用于选举领头 Sentinel
  • 参数 runid:该参数的值可以是 符号或者 Sentinel 的运行 ID。 符号代表命令仅仅用于检测主服务器的客观下线状态,而 Sentinel 的运行 ID 则用于选举领头 Sentinel

2、选举领头 Sentinel

当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个 Sentinel 会进行协商,选举出一个领头 Sentinel,并由领头 Sentinel 对下线主服务器执行故障转移操作。

Sentinel 系统选举领头 Sentinel 的方法是对 Raft 算法的领头选举方法的实现。

选举领头 Sentinel 的规则

Redis 选举领头 Sentinel 的规则:过半数原则

每个发现主服务器进入客观下线的 Sentinel 都会要求其他 Sentinel 将自己设置为局部领头 Sentinel。在一个配置纪元里面,所有 Sentinel 都只有一次将某个 Sentinel 设置为局部领头 Sentinel 的机会,并且局部领头一旦设置,在这个配置纪元里面就不能再更改。

配置纪元实际上就是一个计数器,并没有什么特别的。

每次进行领头 Sentinel 选举之后,不论选举是否成功,所有 Sentinel 的配置纪元(configuration epoch)的值都会自增一次。

Sentinel 设置局部领头 Sentinel 的规则是先到先得:最先向目标 Sentinel 发送设置要求的源 Sentinel 将成为目标 Sentinel 的局部领头 Sentinel,而之后接收到的所有设置要求都会被目标 Sentinel 拒绝。

  • 如果有某个 Sentinel 被半数以上的 Sentinel 设置成了局部领头 Sentinel,那么这个 Sentinel 成为领头 Sentinel。
  • 如果在给定时限内,没有一个 Sentinel 被选举为领头 Sentinel,那么各个 Sentinel 将在一段时间之后再次进行选举,直到选出领头 Sentinel 为止。

因为领头 Sentinel 的产生需要半数以上 Sentinel 的支持,并且每个 Sentinel 在每个配置纪元里面只能设置一次局部领头 Sentinel,所以在一个配置纪元里面,只会出现一个领头 Sentinel。

选举领头 Sentinel 的命令

Redis 检测客观下线状态 / 选举领头 Sentinel 的命令:sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>

  • 参数 ip:被 Sentinel 判断为主观下线的主服务器的 IP 地址
  • 参数 port:被 Sentinel 判断为主观下线的主服务器的端口号
  • 参数 current_epoch:Sentinel 当前的配置纪元,用于选举领头 Sentinel
  • 参数 runid:该参数的值可以是 符号或者 Sentinel 的运行 ID。 符号代表命令仅仅用于检测主服务器的客观下线状态,而 Sentinel 的运行 ID 则用于选举领头 Sentinel

源 Sentinel 发送命令:当一个 Sentinel(源 Sentinel)向另一个 Sentinel(目标 Sentinel)发送该命令,并且命令中的 runid 参数不是 * 符号而是源 Sentinel 的运行 ID 时,这表示源 Sentinel 要求目标 Sentinel 将前者设置为后者的局部领头 Sentinel。


目标 Sentinel 接收命令:目标 Sentinel 在接收到sentinel is-master-down-by-addr <ip> <port> <current_epoch> <runid>之后,将向源 Sentinel 返回一条命令回复,回复中的 leader_runid 参数和 leader_epoch 参数分别记录了目标 Sentinel 的局部领头 Sentinel 的运行 ID 和 配置纪元。

源 Sentinel 接收命令的回复:源 Sentinel 在接收到目标 Sentinel 返回的命令回复之后,会检查回复中 leader_epoch 参数的值和自己的配置纪元是否相同,如果相同的话,那么源 Sentinel 继续取出回复中的 leader_runid 参数,如果 leader_runid 参数的值和源 Sentinel 的运行 ID 一致,那么表示目标 Sentinel 将源 Sentinel 设置成了局部领头 Sentinel。

3、故障转移

在选举产生出领头 Sentinel 之后,领头 Sentinel 将对已下线的主服务器执行故障转移操作,该操作包含以下三个步骤:

  1. 选出新的主服务器:在已下线主服务器属下的所有从服务器里面,挑选出一个从服务器,并将其转换为主服务器。
  2. 修改从服务器的复制目标:让已下线主服务器属下的所有从服务器改为复制新的主服务器。
  3. 将旧的主服务器变为从服务器:将已下线主服务器设置为新的主服务器的从服务器,当这个旧的主服务器重新上线时,它就会成为新的主服务器的从服务器。

1、选出新的主服务器

故障转移操作第一步要做的就是在已下线主服务器属下的所有从服务器中,挑选出一个状态良好、数据完整的从服务器,然后向这个从服务器发送 slaveof no one 命令,将这个从服务器转换为主服务器。


新的主服务器是怎样挑选出来的

领头 Sentinel 会将已下线主服务器的所有从服务器保存到一个列表里面,然后按照以下规则,一项一项地对列表进行过滤:

  1. 根据 在线状态 过滤:删除列表中所有处于下线或者断线状态的从服务器,这可以保证列表中剩余的从服务器都是正常在线的。
  2. 根据 通信情况 过滤:删除列表中所有最近五秒内没有回复过领头 Sentinel 的 info 命令的从服务器,这可以保证列表中剩余的从服务器都是最近成功进行过通信的。
  3. 根据 断连时间 过滤:删除所有与已下线主服务器连接断开超过 down-after- milliseconds 10 毫秒的从服务器:down-after-milliseconds 选项指定了判断主服务器下线所需的时间,而删除断开时长超过 down-after- milliseconds 10 毫秒的从服务器,则可以保证列表中剩余的从服务器都没有过早地与主服务器断开连接,换句话说,列表中剩余的从服务器保存的数据都是比较新的。
  4. 根据 从库的优先级 筛选:之后,领头 Sentinel 将根据从服务器的优先级,对列表中剩余的从服务器进行排序,并选出其中优先级最高的从服务器。
  5. 根据 复制偏移量 筛选:如果有多个具有相同最高优先级的从服务器,那么领头 Sentinel 将按照从服务器的复制偏移量,对具有相同最高优先级的所有从服务器进行排序,并选出其中偏移量最大的从服务器(复制偏移量最大的从服务器就是保存着最新数据的从服务器)。
  6. 根据 运行 ID 筛选:最后,如果有多个优先级最高、复制偏移量最大的从服务器,那么领头 Sentinel 将按照运行 ID 对这些从服务器进行排序,并选出其中运行 ID 最小的从服务器。

2、修改从服务器的复制目标

当新的主服务器出现之后,领头 Sentinel 下一步要做的就是,让已下线主服务器属下的所有从服务器去复制新的主服务器,这一动作可以通过向从服务器发送 slaveof 命令来实现。

3、将旧的主服务器变为从服务器

故障转移操作最后要做的是,将已下线的主服务器设置为新的主服务器的从服务器。

因为旧的主服务器已经下线,所以这种设置是保存在服务器对应的实例结构里面的,当服务器重新上线时,Sentinel 就会向它发送 slaveof 命令,让它成为新主服务器的从服务器。

总结 Sentinel 系统中的周期命令

在 Sentinel 系统中,有很多地方都会以一定的频率向指定的服务器发送命令,下面对所有周期命令进行总结。

检测下线状态的 ping 命令:在默认情况下,Sentinel 会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他 Sentinel 在内)发送 ping 命令,并根据实例对 ping 命令的回复来判断实例是否在线。

获取服务器信息的 info 命令:在一般情况下,Sentinel 以每十秒一次的频率向被监视的主服务器和从服务器发送 info 命令,当主服务器处于下线状态,或者 Sentinel 正在对主服务器进行故障转移操作时,Sentinel 向从服务器发送 info 命令的频率会改为每秒一次。

参考资料

《Redis 设计与实现》书籍

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
存储 缓存 NoSQL
深入解析Redis:一种快速、高效的键值存储系统
**Redis** 是一款高性能的键值存储系统,以其内存数据、高效数据结构、持久化机制和丰富的功能在现代应用中占有一席之地。支持字符串、哈希、列表、集合和有序集合等多种数据结构,适用于缓存、计数、分布式锁和消息队列等场景。安装Redis涉及下载、编译和配置`redis.conf`。基本操作包括键值对的设置与获取,以及哈希、列表、集合和有序集合的操作。高级特性涵盖发布/订阅、事务处理和Lua脚本。优化策略包括选择合适数据结构、配置缓存和使用Pipeline。注意安全、监控和备份策略,以确保系统稳定和数据安全。
310 1
|
4月前
|
NoSQL 关系型数据库 MySQL
Redis之秒杀系统
秒杀是一种高并发场景,通常指的是在短时间内(秒级别)有大量用户同时访问某个商品或服务,争相抢购的情景。在这种情况下,系统需要处理大量并发请求,确保公平性、一致性,并防止因并发而导致的问题,例如超卖、恶意请求等。以下是在高并发秒杀场景下需要考虑的一些关键问题和解决方案:
|
2月前
|
NoSQL Linux Redis
Linux系统中安装redis+redis后台启动+常见相关配置
Linux系统中安装redis+redis后台启动+常见相关配置
|
7天前
|
存储 NoSQL 测试技术
Redis数据存储系统为什么快?
Redis的快速并非偶然,而是深思熟虑的设计理念的结果。通过将数据存储于内存、采用单线程模型、实现非阻塞I/O等独特的技术选择,Redis在高并发和低延迟方面展现了卓越的表现。
37 16
|
12天前
|
缓存 NoSQL Java
【亮剑】分布式锁是保证多服务实例同步的关键机制,常用于互斥访问共享资源、控制访问顺序和系统保护,如何使用注解来实现 Redis 分布式锁的功能?
【4月更文挑战第30天】分布式锁是保证多服务实例同步的关键机制,常用于互斥访问共享资源、控制访问顺序和系统保护。基于 Redis 的分布式锁利用 SETNX 或 SET 命令实现,并考虑自动过期、可重入及原子性以确保可靠性。在 Java Spring Boot 中,可通过 `@EnableCaching`、`@Cacheable` 和 `@CacheEvict` 注解轻松实现 Redis 分布式锁功能。
|
17天前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
22 0
|
24天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
187 10
|
1月前
|
监控 NoSQL 测试技术
解密Redis性能:如何通过性能测试提升系统稳定性和效率
解密Redis性能:如何通过性能测试提升系统稳定性和效率
|
1月前
|
存储 NoSQL Redis
保障数据安全,保障系统稳定:Redis 数据备份与恢复全指南
保障数据安全,保障系统稳定:Redis 数据备份与恢复全指南
|
2月前
|
消息中间件 存储 NoSQL
【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统
【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统