redis读取不到数据_Redis:主从库实现数据一致

Redis通过主从复制确保高可用性,主库写入数据并同步到从库,客户端可从任意从库读取。全量复制时,主库生成RDB文件通过网络发送给从库,同时使用replication buffer记录新数据。网络断开后采用增量复制,通过repl_backlog_buffer缓冲区确保数据不丢失。主从库间为读写分离,保证数据一致性。
摘要由CSDN通过智能技术生成

我们都知道,Redis实现数据持久化有AOF和RDB两个方法,但是即使有这两个方法,也还是存在服务不可用的问题,为啥子嘞?

假设你只有一台服务器,然后这台机器宕机了,这个时候他会以上面的两种方式恢复数据,但是在恢复数据的过程中,新来的数据怎么办?是不是就服务不到了,机器都宕机了还提供个锤子的服务。

Redis之所以牛逼,一方面是因为他快,另一方面是因为高可靠性。所谓的高可靠性就是指,尽量的少丢数据,和服务端尽量少中断。AOF和RDB保证了前者,但是不能保证后者。那咋办呢?

方法肯定是有的,Redis针对和服务端少中断这个问题是这么处理的,将一份数据保存在多个实例上。这样子,即使一台机器完蛋,其他机器也可以接着进行服务,不会导致整个Redis不能使用。

这样子是不是就解决了一开始的问题?我就知道你说是,确实是解决了,但是还有有问题。这么多机器,如何保证每台机器数据的一致性呢?而且客户端的读写操作可以下发给每一台机器吗?

带着问题我们接着絮叨。

这个时候我们的读写分离就闪亮登场了,读写分离肯定要依赖主从库喽,所以Redis有个解决的方法,那就是采用主从库,主库负责写,然后数据同步给从库,客户端读取数据则可以从任意一个库中读取(其实就是从任意一台机器读取)。

来个图?这个图就很形象----图摘自互联网

63196026559366394be6c116d9b91ff2.png

到这里问题又来了,为什么要读写分离呢?我就想不分离行不行!!!

其实你可以想想,如果不分离,那就意味着每台机器都可以写,假设你要改一个数据,发到了第一个机器上,改完之后你发现 卧槽改错了,然后又的改下,这个时候这个操作又发到了另一个机器上。那么这个时候,就有两台机器针对这条数据就有两个结果,再拿的时候,可能就拿到了你第一次改动的那个数据,这个时候是不是就完蛋了?

当然如果你就任性,我就不分离,女朋友都异地了,你还让我写个数据也分离!!!

方法肯定是有的,加锁呗,把它锁住,然后各个机器之间协商修改,这样子就不用分离了,但是你一想这加了锁性能上是不是就有影响了,这对于追求 的你,这能忍?慢的一批那我还用个锤子的Redis!!!

所以还是老老实实的读写分离吧,毕竟快的一批。。。

好吧读写分离就读写分离吧,那啥主库咋给从库同步数据呢?是一次性把所有数据都同步过去还是分批同步?要是同步的过程中网隔壁的二狗子给我把网线拔了,那我还有的救吗?

问得好!!!

那我先说说如何进行第一次同步

当我们启动多个Redis实例的时候,他们相互之间就会根据replicaof这个命令形成主从库的关系。有了这个关系之后他们会按照三个阶段完成第一次同步。

例如 我们有一个库 A 对应的ip和端口号是 1.1.1.1 123 还有一个库B对应的ip是 2.2.2.2 234,

这个时候我们只需要在B上执行下面这行命令。

replicaof 1.1.1.1 123

B就成了A的小弟,并把A的数据复制过来。

我们详细说说复制数据的这三个阶段,再看张图:

426a5a4922c82bf52e9bfb6b931ff713.png

其实图说的已经很清楚了:

一阶段:就是先建立连接,然后从库告诉主库我要同步啦,你给我准备好,然后主库和从库说知道了知道了。

这里有几个小东西解释下,psync这个命令就是告诉主库要同步,然后这个命令里面有两个小玩意,runID这个是Redis启动的时候代表它本身的一个ID,offset这个是复制的进度(第一次复制这个值设为-1) ,还有就是FULLRESYNC这个命令响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库

二阶段:从库拿到数据了,然后要把他保存到库里呀。这个时候就会在本地完成数据的加载,这个时候会用到RDB。

具体就是主库生成RDB文件,然后发给从库,从库会清空当前数据库,然后直接加载这个文件,这个操作就是为了保证数据一致。

你再想想Redis不是单线程的吗?那主库执行同步这个操作不会阻塞吗?阻塞了以后还怎么处理新来的数据呢?

这你就比较年轻了吧。

主库同步是另外fork了一个进程来进行这个操作的,我们说的Redis单线程是数据的读取和写操作是单线程的。数据的持久化操作可不是单线程的,这也是为啥面试的时候面试官问你Redis是单线程还是多线性的?你听了毫无疑问的说单线程,然后面试官看了你一眼说回去等通知吧。你等了两个月还没通知,心里还说这个面试官是个**,不讲武德。

主库如何处理在生成RDB过程中新来的数据呢?

主库会在内存中用专门的replication buffer,记录RDB文件生成后收到的所有写操作。

最后也就是第三阶段,主库会把新来的数据发给从库。

这样是不是就保持了数据的一致性了。

全量复制数据那么多,主库能承受的住吗?

如果从库数量很多,而且都要和主库进行全量复制的话,就会导致主库忙于fork子进程生成RDB文件,进行数据全量同步。fork这个操作会阻塞主线程处理正常请求,从而导致主库响应应用程序的请求速度变慢。此外,传输RDB文件也会占用主库的网络带宽,同样会给主库的资源使用带来压力。

所以这里有个新模式 主-从-从

简单来说就是大哥-小弟模式加一环,变成 大哥-二哥-小弟模式。就是在从库里面选一个老二,然后再从其他从库中选一些库来和这个老二搞主从模式。这样就分担了主库的压力,主库不用和每一个从库进行同步数据。

30f66efa4d37f39dac805c2e02119d1e.png

就是这个图所示。

接下来我们再说说二狗子给我们把网线拔了我们该怎么打他?

哦不对,我们该如何解决这个问题,打二狗子等解决完问题再说。

这同步这个过程中,主从会一直维持一个长连接,如果网络断了,那就无法进行命令交互了,这个时候就无法保证数据的一致性了,这可咋办呢?

Redis2.8之后,有个新的解决方式,就是采用增量复制,增量复制只会把网络断开以后主库收到的这部分数据进行同步给从库。

那么这个操作是如何进行的呢?

奥妙就在于repl_backlog_buffer这个缓冲区,这个东西了不得呀,他是一个环形缓冲区,这个区域内,主库会记录自己写到的位置,从库会记录自己读到的位置。

听到这里是不是有点感觉了?

就是刚开始的时候,主从的位置是一样的,随着主库不断接受写操作,然后位置变变变,距离起始位置的偏移量越来越大,同样从库在复制完写命令之后,他的偏移量也越来越大,正常情况下,这两个位置偏移量差不多,但是一旦网络断开之后,从库的位置就不变了,主库还在那写写写,这个时候同步的话我们是不是只需要把两个偏移量之间的数据同步给从库就可以啦。

恍然大明白了吧。

再来个图看看

3b57ce3794371d9a91e82b662008f315.png

不过还需要考虑一个点,就是因为是个环形缓冲区那就会存在写满这种情况,写满了主库还继续往里面写,那不就会覆盖掉了吗?如过从库读取的慢,是不是就读取不到被覆盖的这些数据了?

所以我们要避免这一问题,我们会动态的调整这个缓冲区的大小,一般的计算公司是

缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小

但在实际业务中考虑到一些突发的请求压力,我们通常需要把这个扩大一倍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值