当我们启动多个Redis实例时, 实例之间可以通过
replicaof
(5.0版本之前采用slaveof)命令形成主库和从库的关系。
主从复制拓扑图如下:
数据同步步骤
-
psync
命令: 该命令由从节点向主节点发送建立连接的请求, 主库会根据从库的参数启动复制. 该命令包含了两个参数:-
主库的runId: runId表示了每个实例启动时随机生成的随机ID, 用来标识redis实例。当从库和主库第一次复制数据时, 因为不知道主库的runID, 因此将 runId设置为”?”
-
-
-
FULLRESYNC
: 由主库向从库响应, 表示第一次采用全量复制。 -
主库采用
BGSAVE
命令生成全量RDB文件, 并将文件发送给从库。 -
从库接收到RDB文件后,会清空当前数据库,然后加载从主库同步过来的RDB文件
-
主库在同步数据到从库期间,能够正常执行其他请求,并将写请求写入到replication buffer
-
主库将replication buffer中的命令,发送给从库
主从模式复制时的主库压力
在复制数据的过程中,有两个耗时操作:
-
生成 RDB文件:
-
虽然采用
BGSAVE
命令异步生成文件,但在fork主进程时,会导致主进程的阻塞。同时会将当前内存数据产生副本,占用更多内存信息。 -
传输RDB文件会占用主库网络带宽,造成请求响应变慢, 无法处理更多客户端请求等问题
-
主-从-从模式
为了缓解主库在较多从库链接导致主库性能下降问题,可以采用主-从-从
模式,基本原理就是减少主库同步数据的压力,转而将部分的同步请求转移到从库执行。
在数据同步完成之后,主从之间依然维持者链接,用于主库将写操作同步到从库,这个过程被称作基于长连接的命令传播
,可以避免频繁建立连接的开销。
主从库断线重连机制
-
在2.8版本之前,主从库断线重连会采用全量同步的方式,重新保持数据一致性。
-
在2.8之后, 则采用增量赋值的方式继续同步。
-
在以上步骤中,主库为了解决在赋值rdb文件的过程中,增量命令的丢失,创建了
replication buffer
,用于缓存写命令。但是在从库断开链接后, 主库会将写命令写入到repl_backlog_buffer
缓冲区中(此时replication buffer
已经不存在)。 -
从库恢复之后,通过
psync
命令将当前offset发送到主库,告知主库从slave_repl_offset
开始发送写命令。
-
什么是repl_backlog_buffer
repl_backlog_buffer
是一个环形缓冲区, 主库记录最新写命令位置, 从库会记录当前已读位置
.
在repl_backlog_buffer
中,有两个关键偏移量:
-
master_repl_offset
: 用于记录当前主库命令偏移量,随着主库接收到的写请求越大,该值越大 -
slave_repl_offset
: 从库在复制完成写命令后,它在缓冲区中的读位置也在逐渐增大。
在正常情况下,这两个偏移量基本相等。
缓冲区大小设置
因为repl_backlog_buffer是一个环形缓冲区, 所以缓冲区写满后, 主库会继续写入。如果从库读取数据缓慢,会导致主库的命令覆盖从库还未读取的命令。导致从库数据不一致性的情况。
repl_backlog_size
通过该参数, 可以调整repl_backlog_size
缓存区的大小,该值的确认可以根据服务器资源充足情况设置较大,或者根据一下公式做评估:
缓冲区空间大小 = 主库写入命令速度 * 命令操作大小 - 主从库间网络传输命令速度 * 操作大小
在考虑业务高峰或者业务攻击等特殊情况,我们可以将缓冲区扩大1倍,保证写入命令不会覆盖从库未同步命令。
repl_backlog_buffer 与 replication buffer 区别
-
repl_backlog_buffer
:为了解决从库断开重连后,能够快速找到主从差异而设计的环形缓冲区,从而避免全量同步带来的性能开销。如果环形缓冲区从库未同步命令被主库覆盖,那么从库重新连接后,必须进行一次重新全量同步。因此建议将该缓冲区设置大一些,防止全量同步的概率。 -
Replication Buffer
: 该缓存是Redis为客户端分配的写出缓冲区,所有数据的交互都是通过该缓冲区进行。-
Redis把数据写入到当前缓存中,然后再把buffer中的数据发送到client socket中完成数据交互
-
在主从同步过程中,从库也是作为Redis客户端存在的,通过该缓冲区将命令发送到从库。
-
如果从库处理数据非常慢,会导致当前缓冲区持续增长,消耗大量内存资源。甚至OOM的错误,所以在Redis中,可以通过
client-ouotput-buffer-limit
参数限制这个buffer的大小,如果超过限制,主库会强制断开这个client链接。
-