07 | 哨兵机制:主库挂了,如何不间断服务?
07 | 哨兵机制:主库挂了,如何不间断服务?
讲述:蒋德钧
时长15:23大小14.09M
哨兵机制的基本流程
主观下线和客观下线
如何选定新主库?
小结
每课一问
赞 152
提建议
精选留言(96)
- Monday置顶2020-08-191、master_repl_offset是存储在主库的,但主库已经挂了,怎么获取的这个值? 可否这样理解,master_repl_offset如事物id一样单调递增,这样的话,就只要不叫从库的slave_repl_offset就行。 至于master_repl_offset真实位置可以对master_repl_offset取模就行。
作者回复: 对master_repl_offset本身的理解没错,master_repl_offset是单调增加的,它的值可以大于repl_backlog_size。Redis会用一个名为repl_backlog_idx的值记录在环形缓冲区中的最新写入位置。 举个例子,例如写入len的数据,那么 master_repl_offset += len repl_backlog_idx += len 但是,如果repl_backlog_idx等于repl_backlog_size时,repl_backlog_idx会被置为0,表示从环形缓冲区开始位置继续写入。 而在实际的选主代码层面,sentinel是直接比较从库的slave_repl_offset,来选择和主库最接近的从库。
共 25 条评论90 - Kaito2020-08-19哨兵在操作主从切换的过程中,客户端能否正常地进行请求操作? 如果客户端使用了读写分离,那么读请求可以在从库上正常执行,不会受到影响。但是由于此时主库已经挂了,而且哨兵还没有选出新的主库,所以在这期间写请求会失败,失败持续的时间 = 哨兵切换主从的时间 + 客户端感知到新主库 的时间。 如果不想让业务感知到异常,客户端只能把写失败的请求先缓存起来或写入消息队列中间件中,等哨兵切换完主从后,再把这些写请求发给新的主库,但这种场景只适合对写入请求返回值不敏感的业务,而且还需要业务层做适配,另外主从切换时间过长,也会导致客户端或消息队列中间件缓存写请求过多,切换完成之后重放这些请求的时间变长。 哨兵检测主库多久没有响应就提升从库为新的主库,这个时间是可以配置的(down-after-milliseconds参数)。配置的时间越短,哨兵越敏感,哨兵集群认为主库在短时间内连不上就会发起主从切换,这种配置很可能因为网络拥塞但主库正常而发生不必要的切换,当然,当主库真正故障时,因为切换得及时,对业务的影响最小。如果配置的时间比较长,哨兵越保守,这种情况可以减少哨兵误判的概率,但是主库故障发生时,业务写失败的时间也会比较久,缓存写请求数据量越多。 应用程序不感知服务的中断,还需要哨兵和客户端做些什么?当哨兵完成主从切换后,客户端需要及时感知到主库发生了变更,然后把缓存的写请求写入到新库中,保证后续写请求不会再受到影响,具体做法如下: 哨兵提升一个从库为新主库后,哨兵会把新主库的地址写入自己实例的pubsub(switch-master)中。客户端需要订阅这个pubsub,当这个pubsub有数据时,客户端就能感知到主库发生变更,同时可以拿到最新的主库地址,然后把写请求写到这个新主库即可,这种机制属于哨兵主动通知客户端。 如果客户端因为某些原因错过了哨兵的通知,或者哨兵通知后客户端处理失败了,安全起见,客户端也需要支持主动去获取最新主从的地址进行访问。 所以,客户端需要访问主从库时,不能直接写死主从库的地址了,而是需要从哨兵集群中获取最新的地址(sentinel get-master-addr-by-name命令),这样当实例异常时,哨兵切换后或者客户端断开重连,都可以从哨兵集群中拿到最新的实例地址。 一般Redis的SDK都提供了通过哨兵拿到实例地址,再访问实例的方式,我们直接使用即可,不需要自己实现这些逻辑。当然,对于只有主从实例的情况,客户端需要和哨兵配合使用,而在分片集群模式下,这些逻辑都可以做在proxy层,这样客户端也不需要关心这些逻辑了,Codis就是这么做的。 另外再简单回答下哨兵相关的问题: 1、哨兵集群中有实例挂了,怎么办,会影响主库状态判断和选主吗? 这个属于分布式系统领域的问题了,指的是在分布式系统中,如果存在故障节点,整个集群是否还可以提供服务?而且提供的服务是正确的? 这是一个分布式系统容错问题,这方面最著名的就是分布式领域中的“拜占庭将军”问题了,“拜占庭将军问题”不仅解决了容错问题,还可以解决错误节点的问题,虽然比较复杂,但还是值得研究的,有兴趣的同学可以去了解下。 简单说结论:存在故障节点时,只要集群中大多数节点状态正常,集群依旧可以对外提供服务。具体推导过程细节很多,大家去查前面的资料了解就好。 2、哨兵集群多数实例达成共识,判断出主库“客观下线”后,由哪个实例来执行主从切换呢? 哨兵集群判断出主库“主观下线”后,会选出一个“哨兵领导者”,之后整个过程由它来完成主从切换。 但是如何选出“哨兵领导者”?这个问题也是一个分布式系统中的问题,就是我们经常听说的共识算法,指的是集群中多个节点如何就一个问题达成共识。共识算法有很多种,例如Paxos、Raft,这里哨兵集群采用的类似于Raft的共识算法。 简单来说就是每个哨兵设置一个随机超时时间,超时后每个哨兵会请求其他哨兵为自己投票,其他哨兵节点对收到的第一个请求进行投票确认,一轮投票下来后,首先达到多数选票的哨兵节点成为“哨兵领导者”,如果没有达到多数选票的哨兵节点,那么会重新选举,直到能够成功选出“哨兵领导者”。展开共 68 条评论881
- 注定非凡2020-08-23一,作者讲了什么? Redis故障转移:主从切换机制哨兵 二,作者是怎么把这事给讲明白的? 1,提出主从切换的三个问题:a,主机状态确认 b,新主库选举 c,新主库通知 2,讲解了哨兵的本质是一个特殊的redis进程(实例),有三个职责:监控,选主,通知 三,为了讲明白,作者讲了哪些要点,有哪些亮点? 1,亮点1:哨兵的本质:是一个redis实例,要做三件事:监控主库,选举新主库,通知客户端和从机(这让我对哨兵理解清晰了很多) 2,要点1:哨兵是通过心跳检测,监控主库状态,主库下线被分为:主观下线和客观下线、 3,要点2:哨兵监控是可能误判的,所以哨兵一般是集群部署,采取投票的形式减少误判 4,要点3:选定新主库规则是先筛选在打分,得分高的会被选为新主库, 5,要点4:筛选规则:从库当前的网络连接状况,以及之前的网络连接状况,筛选中断次数标准可以配置 6,要点5:打分规则:从库的优先级,数据同步状况,Id号大小,可以分为三轮,只要有一轮出现得分高的,就能选出 四,对作者所讲,我有哪些发散性思考? 选举机制,在分布式的场景中经常出现。我在刚开始学习这一类知识的时候,经常会想:那些大神是怎么会想到这种解决方案的? 后来读了一些西方社会运行机制的书,我有所释然。得到一些感悟:大神思考的技术问题解决方案,和他所生活的社会环境有着莫大的关系 五,将来在哪些场景,我能够使用到它? 六,留言区的收获 1,数据同步状况的判断:(感谢@Monday 同学的提问) a:判断哪个从库的数据同步最接近主库,不是拿从库与主库比较,而是从库之间互相比较,谁大谁就是最接近的 b:这样做的原因有二:主库已下线无法获取主库信息,环形缓冲区的位置偏移量是单调递增的(主库的被称为:master_repl_offset,从库的被称为:slave_repl_offset,其实两者本质是相同的,叫不同的名字只是为了区分) 2,哨兵的使用:(感谢 @Kaito 大神简洁明了,无私的分享) a:主库下线,可读不可写,写失败的时间=哨兵切换主从的时间+客户端感知新主库时间 b:主库下线无感知,需要客户端与哨兵配合改造: 1:哨兵主动通知:哨兵需要将最新的主库地址写入自己的pubsub中,客户端需要订阅这个pubsub,当这个pubsub有数据时,客户端就能感知到 2:客户端主动获取:客户端不将主从库写死,而是从哨兵集群中获取,从而始终获取最新的主从地址 c:集群分片模式的Redis集群,可以不使用哨兵机制(我们项目组就是这样的)展开共 7 条评论131
- 悟空聊架构2021-05-08这篇当中提到了很多分布式的理论,但没有细讲,我这里可以再补充下分布式理论相关的内容。希望对大家有所帮助: 现在很多开发同学对分布式的组件怎么使用都有一定经验,也知道 `CAP` 理论和 `BASE` 理论的大致含义。但认真去看分布式算法的真的很少,原因有三: - 担心算法过于复杂,所以花的时间很少。 - 网上的资料能用大白话将分布式算法讲清楚的比较少。 - 学习分布式算法没有一条清晰的路线。 学习分布式协议和算法的路线可以是先学习四大基础理论,作为地基。然后再学习分布式协议和算法。就像是在地基上建房子,地基打好了,才能建更稳固的高楼大厦。 而分布式理论主要有四大块: 四大基础理论 - 拜占庭将军问题 - CAP 理论 - ACID 理论 - BASE 理论 分布式协议和算法主要有八种: 八大分布式协议和算法 - Paxos 算法 - Raft 算法 - 一致性 Hash 算法 - Gossip 协议算法 - Quorum NWR 算法 - FBFT 算法 - POW 算法 - ZAB 协议 如何高效地学习和掌握? 开发分布式系统最关键的就是根据场景特点,选择合适的算法,在一致性和可用性之间妥协折中,而如何做好折中方案,依赖于是否真正理解了各算法的特点。 讲真,如果认真学习这些理论和算法,并清楚了每个算法的特点,适合怎样的场景,当开发分布式系统时,做到知己知彼,才能旗开得胜,实际场景中的问题也能分析清楚并解决掉。 那么这些算法有哪些特点和适用场景,该从哪些方面考量? 分布式算法的四大维度 四大维度:拜占庭容错、一致性、性能、可用性。 这里我做了一个分布式算法四大维度的表格,大家可以对比下: ![分布式算法的对比](http://cdn.jayh.club/blog/20210317/1plCsNXd82rh.png?imageslim) 拜占庭容错 拜占庭容错就是《拜占庭将军问题》中提出的一个模型,该模型描述了一个完全不可信的场景。不可信体现在: - 故障行为。比如节点故障了。 - 恶意行为。比如恶意节点冒充正常节点,发出错误指令。 拜占庭容错的另外一面就是`非拜占庭容错`,又叫故障容错,解决了分布式系统存在故障,但是不存在恶意节点共识的问题,譬如节点所在服务器硬件故障、节点的服务进程崩溃等。 非拜占庭容错算法 在可信的环境,只需要具有故障容错能力,譬如 2PC、TCC、Paxos算法、Raft 算法、Gossip 协议、Ouorum NWR 算法、ZAB 协议。 #### 拜占庭容错算法 而在不可信的环境,需要具有拜占庭容错能力,报错 POW 算法、FBFT 算法。 一致性 一致性分为三种: - 强一致性:保证写操作完成后,任何后续访问都能读到更新后的值。 - 弱一致性:写操作完成后,系统不能保证后续的访问都能读到更新后的值。 - 最终一致性:保证如果对某个对象没有新的写操作,最终所有后续访问都能读到相同的最近更新的值。 在数据库操作层面,我们多使用二阶段提交协议(2PC)保证强一致性。在分布式系统中,多使用 Raft 算法来保证强一致性。如果考虑可用性,则使用 Gossip 协议实现最终一致性,配合 Quorum NWR 算法的三个参数来调节容错能力。而 zookeeper 基于读性能的考虑,通过 ZAB 协议提供最终一致性。 可用性 可用性表示能得到响应数据,但不保证数据最新,强调服务可用。前提条件:访问的是非故障节点。 可用性最强的就是 Gossip 协议了,即时只有一个节点,集群可以提供服务。然后是 Paxos/Raft/ZAB/Quorum NWR/FBFT/POW 算法,能够容忍部分节点故障。 而 2PC、TCC 要求所有节点都正常运行,系统才能正常工作,可用性最低。 性能 性能和可用性联系非常紧密,可用性越高,性能越强。 上面可用性的排序同样适用于性能维度。Gossip 协议可用于 AP 型分布式系统,水平扩展能力强,读写性能最强。 Paxos/Raft/ZAB/Quorum NWR/FBFT/POW 算法都是领导者模型,写性能依赖领导者,读性能依赖一致性的实现。性能处于中等位置。 而 2PC、TCC 实现事务时,需要预留和锁定资源,性能较差。展开共 11 条评论89
- 吕2020-08-19关于第二步,根据master_repl_offset和slave_repl_offset来比较,但此时master已经挂掉了,哨兵如何知道master_repl_offset的,难道哨兵也会存一份主的master_repl_offset?根据之前的学习,salve是不存储master_repl_offset的
作者回复: 文章中为了便于理解,我提到要找的从库,“它的slave_repl_offset需要最接近master_repl_offset”,这种情况下,表明这个从库的复制进度是最快的。 因为不同从库的slave_repl_offset是可以比较的,所以在实际的选主代码中,哨兵在这一步,是通过比较不同从库的slave_repl_offset,找出最大slave_repl_offset的从库。
共 3 条评论47 - Oracleblog2020-08-19主从切换选出新的主后,新的从库同步是需要做一次全量同步吗?
作者回复: 在Redis 4.0前,主从切换后,从库需要和主库做全量同步。但是,在Redis 4.0后,Redis做了优化,从库可以只和新主库做增量同步就行。可以去了解下psync2 :)
共 4 条评论18 - yyl2020-08-21解答: 1.1 绝大部分的读请求,可以响应。由于主库实例挂掉,肯定有小部分数据未被同步至从实例,而这部分数据的读请求是失败的。 1.2 由于主从机制实现了读写分离,主实例挂掉,无法响应写请求。 2. 暂时没想到,看了课代表的解答,蛮详细的展开
作者回复: 1.1 的答案中,如果这小部分数据是新写数据,且未同步的话,发往从库的读请求是会失败的。但如果是更新的数据,且未同步的话,那么从库的读请求会返回旧值。
共 2 条评论12 - 徐鹏2020-08-19有两个问题想请教哈 1.每一个哨兵实例都有整个redis集群的信息,会和每一个redis实例通信吗? 2.在选主过程中,比较从库的salve_repl_offset,是把每个从库salve_repl_offset相互比较还是和master_repl_offset比较?原来的主库不是已经挂了,master_repl_offset 是如何获取到的呢?
作者回复: 回答一下 1. 每个哨兵实例都会和主库、从库通信的,所以能获得从库的信息。 2. 在哨兵选主代码层面,是通过比较不同从库的salve_repl_offset大小来选择的,也就是选择salve_repl_offset最大的那个从库。
9 - ym2021-03-15你好,老师,我有一个疑问,就是主库挂了之后,通过筛选机制选择了一个从库作为新的主库,但是不能保证这个新的主库(旧从库的slave_repl_offset)和之前的主库(旧主库的master_repl_offset)是相同的,有可能是slave_repl_offset < master_repl_offset,那个即使选择了新的主库,那么数据也是丢失了一部分的,这个问题怎么解决呢。共 8 条评论7
- Dovelol2020-08-22老师好,想问下,redis哨兵机制中,每个哨兵就是通过发布消息互相感知的吗?没有在启动时就指定对应哨兵集群的所有ip。
作者回复: Redis哨兵集群中,哨兵配置文件中只用配置主节点的IP、端口号。每个哨兵会和主节点连接,并把自己的连接信息发布到主节点的__sentinel__:hello频道上,同时,每个哨兵会订阅这个频道获取其他哨兵的连接地址,这样,哨兵通过主节点上的__sentinel__:hello频道就相互感知了。 文章也有提到,可以回顾下 :)
共 2 条评论6 - Darren2020-08-19肯定会中断的,但是这么让客户端无感知,说说可能不成熟的想法,请老师和大家指点: 1、如果是读请求,可以直接读取从库,客户端无影响; 2、如果是写请求,可以先把命令缓存到哨兵中(比如说哨兵内部维护一个队列等),等选主成功后,在新的主库进行执行即可。
作者回复: 和你探讨下,你有没有考虑过,如果把写命令缓存到哨兵中,那是需要客户端的命令发送,从发给主库切换到发给哨兵么?另外,哨兵实例一般有多个,你的方案中,写命令缓存到哪个哨兵实例呢?
共 11 条评论6 - Master2020-12-13在优先级和复制进度都相同的情况下,ID 号最小的从库得分最高,会被选为新主库。这种原则是因为啥啊?id号小,为啥得分高啊
作者回复: 在分布式系统中,根据节点ID进行选择时,一般就会选择ID号最小的节点,属于较为常见的默认做法。
共 4 条评论4 - 一步2020-08-21Redis 的实例ID是根据什么进行生成的?
作者回复: Redis server启动时,会生成一个40字节长的随机字符串作为runID,具体算法用的是SHA-1算法。
5 - 小袁2020-08-23老师,如果是主库挂了,从库被提升为主库,这我能够理解。但是你在前面某一篇文章中提到,主从同步最好是通过主从从的方式进行级联,这种拓扑结构下,如果机器或者redis出现问题,整个系统会变成怎样呢?这有点烧脑了共 1 条评论3
- Gopher2021-01-03读了后面的一篇文章想到在主从切换过程中如何让客户端无感知的解决方案: 业务系统也可以订阅对应的状态事件,每次进行写请求的时候,判断下状态,如果是处于切换状态可以,先写入到队列中。
作者回复: 是的,可以让Redis客户端做相应的配合(需要对客户端做相应的开发),如果后端集群正在切换,客户端需要缓存下请求,避免直接发到后端集群。等切换完成,再把请求发到集群处理。
共 2 条评论3 - 意琦行2020-10-04这个判断原则就是:少数服从多数。 按道理说主库下线了应该所有哨兵的结果都是下线才对呀,如果有一个哨兵检测为上线那主库肯定是上线状态吧,为什么这种情况也需要重新选举呢。共 2 条评论2
- 不负青春不负己🤘2020-08-191 sentinel 集群 一般建议是3个节点 还是,多个节点, 怎么保证 sentinal 集群的高可用, 以及集群节点过多 ,会不会 导致选举时间过长, sentinel 选举 类似于 变体raft 协议 2 能不能创建一个微信 或者QQ 群, 一些简单的问题 可以互相交流,共 1 条评论2
- 登山看云海2020-10-23能否讲下客户端在这个过程中如何做到无感知共 1 条评论1
- Geek_c37e492020-08-19主从切换的时候应该是没办法响应写请求的,不过可以把请求缓存记录下来 读请求应该是可以服务的吧1
- 蔡欧2022-08-21 来自广东如何解决Redis主库挂了,Redis依赖可以提供服务:使用哨兵,监控、切换和通知整个Redis集群 如何避免哨兵由于主观下线导致Redis切换:使用哨兵集群,采用少数服从多数的方式 哨兵选举的依据:优先级+进度+序号+网络状态监控(down-after-milliseconds时间内断链的次数) Redis客户端如何自动切换:通过配置客户端哨兵集群配置,可以采用主读或者pubsub方式得到最新的Redis集群地址 如何百分百避免在Redis切换过程数据丢失:Redis切换导致写不可用范围为切换时间+客户端感知新Redis主的时间,这段时间导致Redis写不可用,1 把down-after-milliseconds配置改小,对Redis不可用更加敏感,但是可能导致误判 2 客户端改造成有降级措施,把不可用请求先写入消息队列中,后续等Redis可用后再进行重放展开1