Redis基础篇(七)哨兵机制
上一篇文章介绍了高可靠方案:主从集群模式。通过主从库的读写分离,来保证服务的可靠性。
当某个从库出现故障时,不影响服务的使用,主库仍然可以处理写命令,其他从库可以处理读命令。但主库发生故障,就不能处理写命令了,从库只能处理读命令。这就影响服务的正常使用了,该如何解决呢?
只要找一个从库当主库就可以解决了。但还有三个问题需要处理:
- 主库真的挂了吗?
- 该选择哪个从库作为主库?
- 怎么把新主库的相关信息通知给从库和客户端?
这里就要介绍Redis的哨兵机制了。哨兵机制指在Redis主从集群模式下,实现主从库自动切换。它有效地解决了主从集群模式下故障时的三个问题。
哨兵机制的基本流程
哨兵其实是一个运行在特殊模式下的Redis进行,主从库实例运行的同时,它也在运行。哨兵主要负责的任务有三个:监牢、选主(选择主库)和通知。如下图所示:

- 监控:哨兵进程周期性地给所有主从库发送PING命令,检测它们是否在线运行
- 选主(选择主库):选出新主库
- 通知:让从库执行replicaof,与新主库同步;通知客户端,与新主库连接。
通知任务相对比较简单且容易理解,但在监控和选主这两个任务中,哨兵需要做出两个决策:
- 在监控任务中,哨兵需要判断主库是否处于下线状态;
- 在选主任务中,哨兵要决定选择哪个从库实例作为主库。
下面就介绍一下这两个任务。
哨兵是如何判断主库是否下线
哨兵对主库的下线状态判断有“主观下线”和“客观下线”两种。
- 主线下线,哨兵发现主库或从库对PING命令的响应超时。
- 客观下线,表示主库下线是一个客观事实。
哨兵在判断主从库采用不同方式:
- 哨兵PING从库,如果超时,就直接标记“主观下线”
- 哨兵PING主库,超时不能直接标记“主观下线”,因为可能由于网络阻塞等原因导致误判。
如何解决哨兵误判?
通过哨兵集群,也就是由多个哨兵组成的集群来进行判断。采用少数服从多数,超过N/2+1判断主库为“主观下线”,那就判断主库为“客观下线”。关于哨兵集群,下面会详细介绍。
哨兵是如何选定新主库的?
哨兵选定新主库用四个字概括:“筛选+打分”。简单来说,就是根据筛选条件选出候选从库,然后通过打分,选出最高分的作为新主库。下面说一下筛选条件和打分规则。
筛选条件
首先从库必须在线运行。
其次从库网络状态良好。从库和主库断连超出一定的阈值就把这个从库筛掉。这个阈值就是down-after-milliseconds,表示主从库断连的最大连接超时时间。例如发生超过10次,就认定从库的网络状况不好。
关于down-after-milliseconds,值越小,哨兵就越敏感。当网络拥塞但主库正常,可能会发生不必要的切换。而当主库真的故障了,就切换及时,对业务影响最小。
因此down-after-milliseconds要设置合适的值,既减少不必要的切换,也保证能够及时切换,降低对业务的影响。
打分规则
第一轮,优先级最高的从库得分高。可通过slave-priority配置项,设置从库优先级。
第二轮,和旧主库同步程度最接近的从库得分高。很容易理解,越接近主库,说明数据丢失越少。前面介绍主从复制时,已经知道主从库是通过repl_backlog_buffer保持同步的,所以slave_repl_offset最接近master_repl_offset,得分高。
第三轮,ID号小的从库得分高。每个实例都会有一个ID。这是最后一轮,必须决出胜负,所以就选择最小ID的作为新主库。
到这里,我们对哨兵机制的基本流程有了一个整体的认识,下面我们再来了解关于主从切换的两个问题。
在做主从切换时,客户端能否正常地进行请求操作?
如果客户端使用了读写分离,那么读请求不受影响,而写请求会失败。失败持续时间 = 哨兵切换主从的时间 + 客户端感知到新主库的时间。
如果不想让业务感知到异常,那客户端只能把写失败的请求先缓存起来,或者写入消息队列中间件。这种只适合对写入请求返回值不敏感的业务。
应用程序不感知服务中断,哨兵和客户端要做什么?
当哨兵完成主从切换后,客户端需要及时感知到主库发生了变更,然后把缓存的写请求写入到新库中,保证后续写请求不会再受到影响。具体做法有两方面:
一方面是哨兵主要通知客户端。哨兵在选主后,会把新主库的地址写入自己实例的pub/sub里,客户端需要订阅pub/sub。当切换新主库后,客户端就能拿到新主库的地址,把写请求发到这个新主库即可。
另一方面是客户端主动获取最新的主从地址。如果客户端因为某些原因错过了哨兵的通知,或者哨兵通知后客户端处理失败了,就需要客户端主动获取。
下面再来学习哨兵集群。
哨兵集群
如果哨兵实例在运行时发生故障,主从库还能正常切换吗?
通常,我们在解决一个系统问题的时候,会引入一个新机制,或者设计一层新功能。这里Redis引入哨兵集群来解决哨兵实例的高可靠性问题。
基于pub/sub机制组成哨兵集群
哨兵实例之间可以互相发现,靠的是Redis提供的pub/sub机制,也就是发布/订阅机制。
哨兵和主库建立连接,就可以在主库上发布消息了,比如发布自己的连接信息(IP和端口),同时它也会从主库上订阅消息,获得其他哨兵的连接信息。
当多个哨兵实例都在主库上做了发布和订阅操作,它们之间就能知道彼此的IP地址和端口了。
哨兵除了彼此之间建立起连接形成集群外,还需要和从库建立连接。因为在哨兵的监控任务中,它需要对主从库都进行监控,而且在主从库切换完成后,还需要通知从库,让它们和新主库进行同步。
那么,哨兵是如何知道从库的IP地址和端口的呢?
哨兵通过向主库发送INFO命令来完成的。如下图所示:

通过pub/sub机制,哨兵之间可以组成集群;通过INFO命令,哨兵和从库建立连接,并进行监控。
但是哨兵不能只和主、从库连接。因为,主从库切换后,客户端也需要知道新主库的连接信息。所以哨兵还需要把新主库的信息告诉客户端。
还是可以依赖pub/sub机制来完成哨兵和客户端的信息同步。
基于pub/sub机制的客户端事件通知
本质上,哨兵就是一个运行在特定模式下的Redis实例,只完成监控、选主和通知的任务,因此它也具有pub/sub功能。下面是哨兵提供的一些重要的频道。

知道这些频道后,可以让客户端从哨兵这里订阅消息了。
由哪个哨兵执行主从切换?
在哨兵集群模式下,通过“投标仲裁”,选出哨兵Leader来执行主从切换。投标仲裁的流程如下图所示:

任何一个实例判断主库“主观下线”,就会给其他实例发送is-master-down-by-addr命令。
其他实例会根据自己和主库的连接情况,做出Y或N响应。
一个哨兵获得仲裁所需的赞同票数后,就可以标记主库为“客观下线”。这个票数可以通过哨兵配置文件中的quorum配置项来设定。
再给其他哨兵发送命令,表示希望由自己来执行主从切换,并让其他哨兵进行投票。这个也叫“Leader选举”,满足以下两个条件才能当Leader:
- 拿到半数以上的票数
- 拿到的票数>=quorum
小结
- 哨兵机制是实现Redis不间断服务的保证。
- 哨兵机制的三大任务:监控、选主、通知。
- 为了降低误判率,通过采用哨兵集群,并采用“少数服从多数”的原则,判断主库是否客观下线。
- 哨兵集群的关键机制,包括:
- 基于pub/sub机制的哨兵集群组成过程;
- 基于INFO命令的从库列表,这可以帮助哨兵和从库建立连接;
- 基于哨兵自身的pub/sub功能,实现了客户端的哨兵之间的事件通知。
- 哨兵集群在判断了主库“客观下线”后,经过投票仲裁,选举一个Leader来负责主从切换。
最后再分分享一个经验:要保证所有哨兵实例的配置是一致的,尤其是主观下线的判断值down-after-milliseconds。
参考资料
Redis基础篇(七)哨兵机制的更多相关文章
- 《【面试突击】— Redis篇》-- Redis的主从复制?哨兵机制?
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注左上角编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的主从复制?哨兵机制? 在这个 ...
- redis(5)--redis集群之哨兵机制
哨兵机制 在前面讲的master/slave模式,在一个典型的一主多从的系统中,slave在整个体系中起到了数据冗余备份和读写分离的作用.当master遇到异常终端后,需要从slave中选举一个新的m ...
- redis高可用(哨兵机制)
redis哨兵机制:redis的哨兵系统用于管理多个reids服务器,该系统主要有三个作用: 监控:哨兵 会不断地检查你的主服务(Master)和从服务器(Slave)是否运作正常. 提醒:当被监控的 ...
- Redis高可用方案哨兵机制------ 配置文件sentinel.conf详解
Redis的哨兵机制是官方推荐的一种高可用(HA)方案,我们在使用Redis的主从结构时,如果主节点挂掉,这时是不能自动进行主备切换和通知客户端主节点下线的. Redis-Sentinel机制主要用三 ...
- Java基础篇(JVM)——类加载机制
这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
- Redis基础篇(三)持久化:AOF日志
Redis是内存数据库,但是一旦服务器宕机,内存中的数据将会全部丢失. 最简单的恢复方式是从后端数据库恢复,但这种方式有两个问题: 频繁访问数据库,会给数据库带来巨大的压力: 从数据库中读取相比从Re ...
- Redis基础篇(八)数据分片
现在有一个场景:要用Redis保存5000万个键值对,每个键值对大约是512B,要怎么部署Redis服务呢? 第一个方案,也是最容易想到的,需要保存5000万个键值对,每个键值对约为512B,一共需要 ...
- Lua 学习之基础篇七<Lua Module,Package介绍>
Lua 之Module介绍 包管理库提供了从 Lua 中加载模块的基础库. 只有一个导出函数直接放在全局环境中: [require]. 所有其它的部分都导出在表 package 中. require ...
- redis基础篇
1.redis常见的数据结构 redis是一种以键值对存储的高性能内存数据库,有五种常用的数据类型,string,list,hash,set,zset. 2.redis的过期时间 redis中的key ...
随机推荐
- 老猿学5G扫盲贴:与用户和终端相关的名词UE、SUPI、GPSI、PEI
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 和4 ...
- 第14.1节 通过Python爬取网页的学习步骤
如果要从一个互联网前端开发的小白,学习爬虫开发,结合自己的经验老猿认为爬虫学习之路应该是这样的: 一. 了解HTML语言及css知识 这方面的知识请大家通过w3school 去学习,老猿对于html总 ...
- PyQt(Python+Qt)学习随笔:键盘焦点和逻辑焦点(Logic Focus与Keyboard Focus )
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 Qt中的焦点有键盘焦点和逻辑焦点(Logic Focus与Keyboard Focus )的区分,键 ...
- scrapy爬虫登录edusrc查看漏洞列表
scrapy登录界面的难点在于登录时候的验证码,我们通过使用scrapy.FormRequest向目标网站提交数据(表单提交),同时将验证码显示在本地,手动输入,进而登录. 验证码是类似于这种的,才可 ...
- Python接口测试-使用requests模块发送GET请求
本篇主要记录下使用python的requests模块发送GET请求的实现代码. 向服务器发送get请求:无参数时:r = requests.get(url)带params时:r = requests. ...
- C#中SQL SERVER 2008字符数据类型使用心得
一.尽可能使用Varchar,少使用或者不使用Char字符类型 因为char类型输入的数据长度达不到设计长度,会用空格补足,下面是数据表设计图: 下面是编辑前200行的图: 凡是输入的数据长度达不到设 ...
- 冲刺Day7
每天举行站立式会议照片: 昨天已完成的工作: 1.确认商品分类栏,并前后端交互 2.检查.更正订单模块的代码 3.检查.更正用户模块的代码 今天计划完成的工作: 成员 任务 高嘉淳 检查代码.提供测试 ...
- P6772 [NOI2020]美食家
题目大意 给你一个 \(n\) 个点,\(m\) 条边的有向图,每条边有一个权值 \(w_i\) ,每个节点有一个权值 \(a_i\) . 你从节点 \(1\) 出发,每经过一个节点就可以获得该点的权 ...
- Vulnhub实战靶场:ME AND MY GIRLFRIEND: 1
一.环境搭建 1.官网下载连接:https://www.vulnhub.com/entry/me-and-my-girlfriend-1,409/ 2.下载之后,使用Oracle VM Virtual ...
- Pytest 学习(二十七)- Jenkins+Allure+Pytest的持续集成
一.配置 allure 环境变量 1.下载 allure是一个命令行工具,可以去 github 下载最新版:https://github.com/allure-framework/allure2/re ...