Redis:主从复制

参考资料:

《Redis 复制》

《redis:主从复制缓冲区》

《Redis主从复制》

《深入学习Redis:主从复制》

前文:

《Redis:持久化RDB与AOF》

        写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。

目录

一、主从复制简介

        1、主从复制是什么

        2、主从复制有哪些作用

二、主从复制详解

        1、复制方式

        2、全量复制

        (1)确立主从关系

        (2)全量复制的流程

        3、增量复制

        (1)复制偏移量(replication offset)

        (2)复制积压缓冲区(replication backlog)

        (3)断开重连的注意点 

三、心跳检测

        1、检测主从连接状态

        2、辅助实现 min-slaves 选项

        3、检测命令丢失

四、补充

        1、主库建议开启持久化

        2、全量复制为什么使用RDB而不是AOF        

        3、读写分离时怎么删除过期数据


一、主从复制简介

        1、主从复制是什么

        主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。

        从 Redis 2.6 开始, 从服务器支持只读模式, 并且该模式为从服务器的默认模式。只读模式由 redis.conf 文件中的 slave-read-only 选项控制, 也可以通过 CONFIG SET parameter value (opens new window)命令来开启或关闭这个模式。只读从服务器会拒绝执行任何写命令, 所以不会出现因为操作失误而将数据不小心写入到了从服务器的情况。

        一个主服务器可以有多个从服务器,一个从服务器只能有一个主服务器,并且不支持主主复制。

        不仅主服务器可以有从服务器,从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个主从链。

        2、主从复制有哪些作用

  • 数据备份:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复。
  • 读写分离:由主节点提供写服务,由从节点提供读服务,提高Redis服务器的并发量。

        实现主从复制后可以将读操作分摊到从节点上:

  • 读操作:主库、从库都可以接收;
  • 写操作:首先到主库执行,然后,主库将写操作同步给从库。

二、主从复制详解

        1、复制方式

  • 全量复制:比如第一次同步时
  • 增量复制:只会把主从库网络断连期间主库收到的命令,同步给从库

        Redis在2.8版本之前只有全量复制,而2.8版本后有全量和增量复制。

        2、全量复制

        (1)确立主从关系

                Redis 通过 replicaof host port (5.0前使用slaveof)命令来让一个Redis服务成为另一个Redis服务的从库。

                例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据:

replicaof 172.16.19.3 6379

        (2)全量复制的流程

        完整复制流程如下:

  • 第一步,从库向主库发送PSYNC ? -1 命令,主动请求进行完整重同步

        这一步是主从库间建立连接、协商同步的过程,主要是为全量复制做准备。在这一步,从库和主库建立起连接,并告诉主库即将进行同步,主库确认回复后,主从库间就可以开始同步了。 

        从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数。

        runID是Redis启动时给每个实例创建的唯一ID,用以标识不同的Redis实例,当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。offset则表示复制进度(也叫复制偏移量),主要为增量复制服务,这里因为是全量复制,所以使用-1表示。

  • 第二步,主库向从库发送FULLRESYNC响应命令并带上两个参数:主库 runID 和主库目前的复制进度 offset
  • 第三步,主库执行 bgsave 命令,生成 RDB 文件,并发给从库。

        此时,主库为了响应从库的复制请求,会调用bgsave 命令,生成 RDB 文件,接着将文件发给从库。(RDB在此前的持久化内容中已做过介绍,这里不再赘述,不了解的可以看这里《Redis:持久化RDB与AOF》

        从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件。这是因为从库在通过 replicaof 命令开始和主库同步前,可能保存了其他数据。为了避免之前数据的影响,从库需要先把当前数据库清空。

  • 第四步,将发送过程中收到的指令存储到replication buffer中,并发送给从库

        就像RDB文件生成过程中Redis不停止提供服务一样,从库在接收并载入RDB文件的过程中,主库仍然可以写入数据,那怎么将这部分数据传给从库呢?

        为了处理这部分数据,主库为每个连接进来的从库准备了一个replication buffer缓冲区,这段时间内写入的数据都会被存入这个replication buffer中,等从库载入完RDB文件后,就将replication buffer中的数据推送过去。

        如上,全量复制的完成流程就完成了,后续主库接收到的写命令都会被主库传递给所有从库,以保证数据的一致性。

        对于第一次建立主从关系的2台实例,全量复制功能可用很好完成任务;但是对于断线后重复制,由于每次任然需要生成 RDB 并传输。

        了解过前文持久化的朋友应该知道,生成RDB文件是比较耗费资源的,同时,主服务器传输 RDB 文件给从服务器,这个操作会耗费主从服务器大量的网络资源,并对主服务器响应时延产生影响。而对从服务器而言,载入 RDB 文件期间,会阻塞其他命令请求,这也会导致响应效率的降低。为此,Redis2.8之后便提供了增量复制的功能以应对这种情况。

        

        3、增量复制

        在2.8以前只有全量复制,如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大。因此 从Redis 2.8 开始提供了增量复制的功能,在网络断了之后,主从库会采用增量复制的方式继续同步。

        (1)复制偏移量(replication offset)

        主服务器和从服务器会分别维护一个复制偏移量。如果主从服务器的复制偏移量相同,则说明二者的数据库状态一致;反之,则说明二者的数据库状态不一致,此时从库需要使用增量复制来同步缺失的这一部分数据。

        (2)复制积压缓冲区(replication backlog)

        主库的写命令,除了传给从库后,还会写入replication backlog(全局唯一),这是一个固定长度的先进先出(FIFO)队列,默认大小为 1MB。其在内存中是一个环形结构。       

                                 

         如上图,主库按照顺时针方向写命令,主库最新写入的位置即为上文提到的主库的偏移量,这里叫master offset。假设从库在set key2 2后断开连接,也就是上图中slave offset的位置,当它重连时,再次给主库发送psync指令时,会带上自己的offset(注意和全量复制的区别,全量复制时offset设置为-1)。根据上文,我们知道主库发现从库的偏移量与自己不一致,需要进行增量复制。此时主库会计算出master offset与slave offset之间的指令,并发送给该为从库准备的replication buffer中,进而发送给从库。从库进行写入后便又恢复到和主库一致的状态。

        上文就是整个增量复制的过程,我们通过下图展示出来

        (3)断开重连的注意点 

        断开重连并不一定总是增量复制

        1、整个replication backlog是个环形结构,也就是说最新的写命令会将最老的写命令覆盖。换句话说,如果从库断开时间太久,环形缓冲区被主库的写命令覆盖了,那么从库连上主库后只能通过全量复制来获取数据了。所以replication backlog配置要尽量大一些,可以降低主从断开后全量复制的概率。

        2、上文中有提到每个实例有自己的RunID,这个值在服务器启动时自动生成,由 40 个随机的十六进制字符组成。从库断开重连时会将之前主库的RunID一起发送过去(这里注意和全量复制(或者说是第一次连接)的区别,全量复制时发送的RunID是“?”),主库会判断这个RunID是否为自己,如果不是,则会和全量复制时一样返回FULLRESYNC响应命令,告知从库需要进行全量复制。

三、心跳检测

        在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:

// replication_offset为从服务器当前的复制偏移量
REPLCONF ACK <replication_offset>

        发送 REPLCONF ACK 命令对于主从服务器有三个作用:

  • 检测主从服务器的网络连接状态。
  • 辅助实现 min-slaves 选项。
  • 检测命令丢失

        1、检测主从连接状态

        可以通过发送和接收 REPLCONF ACK 命令来检查主从服务器之间的网络连接是否正常:如果主服务器超过一秒没有收到从服务器发来的 REPLCONF ACK 命令,那么主服务器就知道主从服务器之间的连接出现问题了。

        可以通过向主服务器发送 INFO replication 命令,在列出的从服务器列表的 lag 一栏中,可以看到从服务器向主服务器发送 REPLCONF ACK 命令已经过去多少秒在一般情况下,lag的值应该在0秒或者1秒之间跳动,如果超过1秒的话,那么说明主从 服务器之间的连接出现了故障。

        2、辅助实现 min-slaves 选项

        在Redis中,为了避免主从之间产生较大的数据丢失,提供了min-slaves-to-write和min-slaves-max-lag两个选项可以防止主服务器在不安全的情况下执行写命令。

min-slaves-to-write 3
min-slaves-max-lag 10

        以上配置表示:从服务器小于 3 个,或三个从服务器的延迟(lag)都大于等于 10 秒时,主服务器将拒绝执行写命令,直至故障恢复。

        3、检测命令丢失

        如果因为网络故障,主服务传播给从服务器的写命令丢失,那么从服务器定时向主服务器发送 REPLCONF ACK 命令时,主服务器将发觉从服务器的复制偏移量少于自己的。然后,主服务器就会根据从服务器提交的复制偏移量,在复制积压缓冲区中找到从服务器缺少的数据,并将这些数据重新发送给从服务器

四、补充

        1、主库建议开启持久化

        假设主库不开启持久化,那么当主库自动重启后,数据全部丢失,成为空库。此时从库继续复制主库的数据,发现无数据,从库上的复制数据也会被删除。

         因此在允许自动重启的主库中不开启持久化是非常危险的,如果确实有关闭主库持久化的需要,则应禁止实例自动重启。

        2、全量复制为什么使用RDB而不是AOF        

        在前文(《Redis:持久化RDB与AOF》)中,我们介绍了2种持久化的方法RDB与AOF。

        AOF实时性更高,但使用的指令追加的方式,且载入数据时需要根据这些指令逐条操作数据来实现从库与主库的数据一致,这其中一些不乏冗余操作,例如一个数据被新增后删除,AOF文件中就会有一条add一条del指令,但这2条指令执行后库中并没有新的数据,完全可以跳过。

        以上的缺点导致AOF文件较大,更耗费资源(包括主从库间的网络传输与从库的载入)。

        而RDB虽然时效性差了一些,但生成的是主库数据的快照,文件小,载入快,因此比AOF更适合用作做全量复制。

        3、主从复制怎么删除过期数据

        在前文(《Redis:内存淘汰机制》)中我们介绍了过期数据的删除策略,包括定期删除与惰性删除。        

        在主从复制场景下,为了保证主从库的数据一致性,从库不会主动删除数据,而是由主库控制从库中过期数据的删除,当主库删除数据时会将del指令传播给从库,进而将从库中的过期数据进行删除。

        由于主库的惰性删除和定期删除策略,都不能保证主库及时对过期数据执行删除操作,因此,当客户端通过Redis从库读取数据时,很容易读取到已经过期的数据。 Redis 3.2中,从节点在读取数据时,增加了对数据是否过期的判断:如果该数据已过期,则不返回给客户端;将Redis升级到3.2可以解决数据过期问题。

    

        

        

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值