美文网首页
《【面试突击】— Redis篇》-- Redis的主从复制?哨兵

《【面试突击】— Redis篇》-- Redis的主从复制?哨兵

作者: JAVA一方 | 来源:发表于2020-02-11 16:49 被阅读0次

    Redis如何保证高并发,高可用?

    高并发:redis的单机吞吐量可以达到几万不是问题,如果想提高redis的读写能力,可以用redis的主从架构,redis天热支持一主多从的准备模式,单主负责写请求多从负责读请求,主从之间异步复制,把主的数据同步到从。

    高可用:首先利用redis的主从架构解决redis的单点故障导致的不可用,然后如果使用的是主从架构,那么只需要增加哨兵机制即可,就可以实现,redis主实例宕机,自动会进行主备切换。以此来达到redis的高可用。

    你刚才说主从复制,那你能具体聊一下主从复制的原理吗?

    在redis主从架构中,master负责接收写请求,写操作成功后返回客户端OK,然后后将数据异步的方式发送给多个slaver进行数据同步,不过从redis 2.8开始,slave node会周期性地确认自己每次复制的数据量。

    当启动一个slave node的时候,它会发送一个PSYNC命令给master node。如果slave node是重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接master node,那么会触发一次full resynchronization全量复制。

    开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存(内存缓冲区)中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。

    另外slave node做复制的时候,是不会block master node的正常工作的,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了。slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量。slave与高可用性有很大的关系。

    Tips:边讲边画图最好了。

    主从复制的过程中如果因为网络原因停止复制了会怎么样?

    如果出现网络故障断开连接了,会自动重连的,从redis 2.8开始,就支持主从复制的断点续传,可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。

    master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node。

    master node会在内存中创建一个backlog,master和slave都会保存一个replica offset,还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制。

    但是如果没有找到对应的offset,那么就会执行一次resynchronization全量复制。

    好的,那你能说说什么是哨兵有什么作用吗?

    哨兵是redis集群架构中非常重要的一个组件,主要功能如下

    (1)集群监控,负责监控redis master和slave进程是否正常工作

    (2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员

    (3)故障转移,如果master node挂掉了,会自动转移到slave node上

    (4)配置中心,如果故障转移发生了,通知client客户端新的master地址

    哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作

    (1)故障转移时,判断一个master node是宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题

    (2)即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。

    目前采用的是sentinal 2版本,sentinal 2相对于sentinal 1来说,重写了很多代码,主要是让故障转移的机制和算法变得更加健壮和简单。

    如果有面试问题的可以一起来探讨:https://shimo.im/docs/VqQR6tPrpR3C3tjq/

    为什么redis哨兵集群只有2个节点无法正常工作?

    如果两个哨兵实例,即两个redis实例,一主一从的模式。

    则redis的配置quorum=1,表示一个哨兵认为master宕机即可认为master已宕机。

    但是如果是机器1宕机了,那哨兵1和master都宕机了,虽然哨兵2知道master宕机了,但是这个时候,需要majority,也就是大多数哨兵都是运行的,2个哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2个哨兵都运行着,就可以允许执行故障转移。

    但此时哨兵1没了就只有1个哨兵了了,此时就没有majority来允许执行故障转移,所以故障转移不会执行。

    主备切换的时候会有数据丢失的可能吗?

    会有,而且有两种可能,一种是异步复制,一种是脑裂导致的数据丢失。

    简单描述一下这两种数据丢失的过程吧

    好的,第一种很好理解,因为master 到 slave的复制是异步的,所以可能有部分数据还没复制到slave的时候,master就宕机了,此时这些部分数据就丢失了。虽然master会做持久化,但是哨兵将slave提升为master后,如果旧的master这时候好了,会当做slave挂到新的master上,从新的master同步数据,原来的数据还是会丢失。

    第二种,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着,即集群分区现象。此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master.

    这个时候,集群里就会有两个master,也就是所谓的脑裂。

    此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续向旧master写数据,这部分数据可能就丢失了。因此旧master再次恢复的加入到主从结构中时,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据,原来的写到旧master的数据就丢失了。

    那有什么办法解决这个数据丢失的问题吗?

    数据丢失的问题是不可避免的,但是我们可以尽量减少。

    在redis的配置文件里设置参数

    min-slaves-to-write 1

    min-slaves-max-lag 10

    min-slaves-to-write默认情况下是0,min-slaves-max-lag默认情况下是10。

    上面的配置的意思是要求至少有1个slave,数据复制和同步的延迟不能超过10秒。如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了。

    上面两个配置可以减少异步复制和脑裂导致的数据丢失。

    设置了这俩参数具体是怎么减少数据丢失的呢?

    以上面配置为例,这两个参数表示至少有1个salve的与master的同步复制延迟不能超过10s,一旦所有的slave复制和同步的延迟达到了10s,那么此时master就不会接受任何请求。

    我们可以减小min-slaves-max-lag参数的值,这样就可以避免在发生故障时大量的数据丢失,一旦发现延迟超过了该值就不会往master中写入数据。

    那么对于client,我们可以采取降级措施,将数据暂时写入本地缓存和磁盘中,在一段时间后重新写入master来保证数据不丢失;也可以将数据写入kafka消息队列,隔一段时间去消费kafka中的数据。

    通过上面两个参数的设置我们尽可能的减少数据的丢失,具体的值还需要在特定的环境下进行测试设置。

    相关文章

      网友评论

          本文标题:《【面试突击】— Redis篇》-- Redis的主从复制?哨兵

          本文链接:https://www.haomeiwen.com/subject/kpoczctx.html