技术交流28群

服务热线

135-6963-3175

微信服务号

redis主从复制简介、原理流程 更新时间 2022-3-6 浏览1044次

一个master可有多个slave,一个slave只对应一个master

master:

    写数据:执行写操作时,将变化的数据自动同步到slave

    读

slave(冷备):

    写数据(禁止)

    读(冷备,cluster不会转发,需要客户端实现或者通过proxy但会牺牲部分一致性)

        (在从节点上使用 readonly 命令,可以让从节点允许 get 功能)

主从复制流程:

    1、建立连接阶段,salve去连接master

    2、数据同步阶段,master将数据同步到slave

    3、当向master中写操作后,将数据同步到slave

(1)初次全量同步:

当redis服务器第一次向主master发送slaveof命令时候,redis从服务器进行一次全量同步:

1646576663607.png

        slave服务器向master发送psync命令(此时发送的是psync ? -1),告诉master我需要同步数据了。
        master接收到psync命令后会进行BGSAVE命令生成RDB文件快照。
        生成完后,会将RDB文件发送给slave。
        slave接收到文件会载入RDB快照,并且将数据库状态变更为master在执行BGSAVE时的状态一致。
        master会发送保存在缓冲区里的所有写命令,告诉slave可以进行同步了
        slave执行这些写命令。

(2)增量命令传播:

slave已经同步过master了,那么如果后续master进行了写操作,比如说一个简单的set name redis,那么master执行过当前命令后,会将当前命令发送给slave执行一遍,达成数据一致性。

(3)重新复制:

当slave断开重连之后会进行重新同步,重新同步分完全同步和部分同步

1646576662675.png

        当slave断开重连后,会发送psync 命令给master。
        master收到psync后会返回+continue回复,表示slave可以执行部分同步了。
        master发送断线后的写命令给slave
        slave执行写命令。

当slave发送psync命令给master之后,master还需要根据以下三点判断是否进行部分同步。

1、服务器运行id

每个redis服务器开启后会生成运行ID。当进行初次同步时,master会将自己的ID告诉slave,slave会记录下来,当slave断线重连后,发现ID是这个master的就会尝试进行部分重同步。当ID与现在连接的master不一样时会进行完整重同步

2、复制偏移量

复制偏移量包括master复制偏移量和slave复制偏移量,当初次同步过后两个数据库的复制偏移量相同,之后master执行一次写命令,那么master的偏移量+1,master将写命令给slave,slave执行一次,slave偏移量+1,这样版本就能一致。

3、复制积压缓冲区

复制积压缓冲区是由master维护的固定长度的先进先出的队列。当slave发送psync,会将自己的偏移量也发送给master,当slave的偏移量之后的数据在缓冲区还存在,就会返回+continue通知slave进行部分重同步。当slave的偏移量之后的数据不在缓冲区了,就会进行完整重同步。

1646576664318.png

总结:
当slave断开重连后,会发送psync 命令给master。
master首先会对服务器运行id进行判断,如果与自己相同就进行判断偏移量
master会判断自己的偏移量与slave的偏移量是否一致。
如果不一致,master会去缓冲区中判断slave的偏移量之后的数据是否存在。
如果存在就会返回+continue回复,表示slave可以执行部分同步了。
master发送断线后的写命令给slave
slave执行写命令。

主从复制常见问题:

1、slave本身有数据,会怎么样?

slave先删除自身的数据,再用rdb文件加载。

2、生成rdb文件的过程中,客户端写命令怎么处理?

保存到内存缓存中,rdb发送完成后发送到slave。 

3、Redis复制如何处理key过期的? 

(1)副本不会使key过期,而是等待主机使key过期。当主机使key过期(或由于LRU而将其逐出)时,它将合成一个DEL命令,该命令将传输到所有副本。

(2)但是,由于主机驱动的expire,有时副本可能仍然具有逻辑上已过期的内存key,因为主服务器无法及时提供DEL命令。为了处理这个问题,副本使用它的逻辑时钟来报告一个key不存在,只用于不违反数据集一致性的读取操作(因为来自主服务器的新命令将到达)

(3)在Lua脚本执行期间,不执行key过期。当Lua脚本运行时,从概念上讲,主节点中的时间是冻结的,因此给定的键在脚本运行的所有时间内都将存在或不存在。这可以防止key在脚本中间过期,并且需要key才能以保证在数据集中具有相同效果的方式将相同的脚本发送到副本。

一旦slave升级为主mater,它将开始独立地使key过期,并且不需要旧master的任何帮助。

slave也可以有自己的slave,从redis4.0开始,slave都会从主节点接收完全相同的复制流。(实际上,除了主从同步,redis也可以从从同步,我们在这里统一描述为主从同步。降低主节点压力)

4、同步

(1)增量同步

从节点同步数据的时候不会影响主节点的正常工作,也不会影响自己对外提供读服务的功能,从节点会用旧的数据来提供服务,当同步完成后,需要删除旧数据集,加载新数据,这个时候才会暂停对外服务。

因为内存的 buffer 是有限的,所以 redis 主节点不能将所有的指令都记录在内存 buffer 中。redis 的复制内存 buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。

1646576664203.png

(2)快照同步

如果节点间网络通信不好,那么当从节点同步的速度不如主节点接收新写请求的速度时,buffer 中会丢失一部分指令,从节点中的数据将与主节点中的数据不一致,此时将会触发快照同步。(需要配置一个合适的复制 buffer 大小参数,避免快照复制的死循环。)

(3)无盘复制

主节点在进行快照同步时,会进行大量的文件 IO 操作,特别是对于非 SSD 磁盘存储时,快照会对系统的负载产生较大影响。特别是当系统正在进行 AOF 的 fsync 操作时如果发生快照复制,fsync 将会被推迟执行,这就会严重影响主节点的服务效率。

从 Redis 2.8.18 版开始支持无盘复制。所谓无盘复制是主节点会一边遍历内存,一遍将序列化的内容发送到从节点,而不是生成完整的 RDB 文件后才进行 IO 传输从节点还是跟之前一样,先将接收到的内容存储到磁盘文件中,再进行一次性加载。


附主从复制详细流程:

(1) 在从节点的配置文件中的slaveof配置项中配置了主节点的IP和port后,从节点就知道自己要和那个主节点进行连接了(cluster模式不需要)。

(2) 从节点内部有个定时任务,会每秒检查自己要连接的主节点是否上线,如果发现了主节点上线,就跟主节点进行网络连接。注意,此时仅仅是取得连接,还没有进行主从数据同步。

(3) 从节点发送ping命令给主节点进行连接,如果设置了口令认证(主节点设置了requirepass),那么从节点必须发送正确的口令(masterauth)进行认证。

(4) 主从节点连接成功后,主从节点进行一次快照同步。事实上,是否进行快照同步需要判断主节点的run id,当从节点发现已经连接过某个run id的主节点,那么视此次连接为重新连接,就不会进行快照同步。相同IP和port的主节点每次重启服务都会生成一个新的run id,所以每次主节点重启服务都会进行一次快照同步,如果想重启主节点服务而不改变run id,使用redis-cli debug reload命令。

(5) 当开始进行快照同步后,主节点在本地生成一份rdb快照文件,并将这个rdb文件发送给从节点,如果复制时间超过60秒(配置项:repl-timeout),那么就会认为复制失败,如果数据量比较大,要适当调大这个参数的值。主从节点进行快照同步的时候,主节点会把接收到的新请求命令写在缓存 buffer 中,当快照同步完成后,再把 buffer 中的指令增量同步到从节点。如果在快照同步期间,内存缓冲区大小超过256MB,或者超过64MB的状态持续时间超过60s(配置项:client-output-buffer-limit slave 256MB 64MB 60),那么也会认为快照同步失败。

(6) 从节点接收到RDB文件之后,清空自己的旧数据,然后重新加载RDB到自己的内存中,在这个过程中基于旧的数据对外提供服务。如果主节点开启了AOF,那么在快照同步结束后会立即执行BGREWRITEAOF,重写AOF文件。

(7) 主节点维护了一个backlog文件,默认是1MB大小,主节点向从节点发送全量数据(RDB文件)时,也会同步往backlog中写,这样当发送全量数据这个过程意外中断后,从backlog文件中可以得知数据有哪些是发送成功了,哪些还没有发送,然后当主从节点再次连接后,从失败的地方开始增量同步。这里需要注意的是,当快照同步连接中断后,主从节点再次连接并非是第一次连接,所以进行增量同步,而不是继续进行快照同步。

(8) 快照同步完成后,主节点后续接收到写请求导致数据变化后,将和从节点进行增量同步,遇到 buffer 溢出则再触发快照同步。

(9) 主从节点都会维护一个offset,随着主节点的数据变化以及主从同步的进行,主从节点会不断累加自己维护的offset,从节点每秒都会上报自己的offset给主节点,主节点也会保存每个从节点的offset,这样主从节点就能知道互相之间的数据一致性情况。从节点发送psync runid offset命令给主节点从而开始主从同步,主节点会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,也可能是CONTINUE触发增量复制。

(10) 主从节点因为网络原因导致断开,当网络接通后,不需要手工干预,可以自动重新连接。

(11) 主节点如果发现有多个从节点连接,在快照同步过程中仅仅会生成一个RDB文件,用一份数据服务所有从节点进行快照同步。

(12) 从节点不会处理过期key,当主节点处理了一个过期key,会模拟一条del命令发送给从节点。

(13) 主从节点会保持心跳来检测对方是否在线,主节点默认每隔10秒发送一次heartbeat,从节点默认每隔1秒发送一个heartbeat。

(14) 建议在主节点使用AOF+RDB的持久化方式,并且在主节点定期备份RDB文件,而从节点不要开启AOF机制,原因有两个,一是从节点AOF会降低性能,二是如果主节点数据丢失,主节点数据同步给从节点后,从节点收到了空的数据,如果开启了AOF,会生成空的AOF文件,基于AOF恢复数据后,全部数据就都丢失了,而如果不开启AOF机制,从节点启动后,基于自身的RDB文件恢复数据,这样不至于丢失全部数据。RDB和AOF机制可以参考详解 redis-4.x 持久化机制

待补充。。。

参考:

blog.csdn.net/qq_41724691/article/details/86616266

cnblogs.com/amei0/p/8177076.html

cloud.tencent.com/developer/article/1398245

blog.csdn.net/m0_37989980/article/details/107766242