type
status
date
slug
summary
tags
category
icon
password
创建时间
Sep 19, 2024 03:55 PM
主从库模式
主从库模式,主从库之间采用读写分离的方法:
读操作:主库、从库都可以接受
写操作:首先到主库执行,然后,主库将写操作同步到从库

为什么要采用读写分离的方式呢?
如果不采用读写分离的方式,数据需要多个 Redis 之间同步,可能涉及到加锁等操作,且 Redis 之间是基于网络通信的,每个 Redis 都需要将自己的数据同步到其他实例上,可能会造成网络信息的拥堵。
而采用读写分离的方法,所有写操作仅仅在主库上进行操作,避免了为保证数据不一致带来的额外开销。其次,仅仅需要将主库的信息同步到从库上,不需要每个实例之间通信,在一定程度上缓解了网络通信的拥堵。
操作命令──replicaof
(Redis 5.0 之前使用 slaveof
)命令
例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据
主从库间数据第一次同步的三个阶段

- 主从库间建立连接、协商同步
psync
命令──主库的runID
和复制进度offset
runID
,是每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实 例。当从库和主库第一次复制时,因为不知道主库的runID
,所以将runID
设 为“?
”。offset
,此时设为1
,表示第一次复制。FULLRESYNC
命令──主库runID
和主库目前的复制进度offset
- 两个参数的作用同上
- 注意:
FULLRESYNC
响应表示第一次复制采用的全量复制。
- 主库将所有数据同步给从库──依赖与 RDB 文件
- 流程
- 主库生成 RDB 文件,将其发送给从库
- 从库接受 RDB 文件,清空当前数据库,加载 RDB 文件
- 注:同步过程中,主库可以正常响应请求。新来的写操作会存放到
replication buffer
中,其中 RDB 文件生成后收到的所有写操作。
- 主库会把第二阶段执行过程中新收到的写命令,再发送给从库──传输的是命令
主从级联模式──“主-从-从”模式分担全量复制时的主库压力
两个耗时操作:生成 RDB 操作和传输 RDB 文件。
当从库数量众多,且都需要和主库进行全量服务,会给主库的资源带来压力。原因是所有的从库都是和主库连接,所有的全量复制也都是和主库进行的。我们可以通过“主 - 从 - 从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上。

全量复制完成之后──基于长连接的命令传播
一旦主从库完成了全量复制,它们之间就会一直维护一个网络连接,主库会通过这个连接将后续陆续收到的命令操作再同步给从库,这个过程也称为基于长连接的命令传播,可以避免频繁建立连接的开销。长连接复制是主从库正常运行后的常规同步阶段。在这个阶段中,主从库之间通过命令传播实现同步。
主从库网络断联──增量复制
当主从库断连后,主库会把断连期间收到的写操作命令,写入
replication buffer
,同时也会把这些操作命令也写入 repl_backlog_buffer
这个缓冲区。repl_backlog_buffer
是一个环形缓冲区,主库会记录自己写到的位置(master_repl_offset
) ,从库则会记录自己已经读到的位置(slave_repl_offset
) 。
在网络断连阶段,主库可能会收到新的写操作命令,所以,一般来说,
master_repl_offset
会大于 slave_repl_offset
。主从库的连接恢复之后,从库首先会给主库发送 psync
命令,并把自己当前的 slave_repl_offset
发给主库,主库会判断自己的 master_repl_offset
和 slave_repl_offset
之间的差距。此时,主库只用把 master_repl_offset
和 slave_repl_offset
之间的命令操作同步给从库就行。
注:如果从库的读取速度比较慢,就有可能导致从库还未读取的操作被主库新写的操作覆盖了,这会导致主从库间的数据不一致。──调整
repl_backlog_size
参数缓冲空间的计算公式是:缓冲空间大小 = 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小。而
repl_backlog_size
= 缓冲空间大小 * 2举个例子,如果主库每秒写入 2000 个操作,每个操作的大小为 2KB,网络每秒能传输 1000 个操作,那么,有 1000 个操作需要缓冲起来,这就至少需要 2MB 的缓冲空间。否则,新写的命令就会覆盖掉旧操作了。为了应对可能的突发压力,我们最终把
repl_backlog_size
设为 4MB。不过,如果并发请求量非常大,连两倍的缓冲空间都存不下新操作请求的话,此时,主从库数据仍然可能不一致。针对这种情况,一方面,你可以根据 Redis 所在服务器的内存资源再适当增加
repl_backlog_size
值,比如说设置成缓冲空间大小的 4 倍,另一方面,你可以考虑使用切片集群来分担单个主库的请求压力。总结
三种模式:
- 全量复制:主从库直接第一次同步,会采用全量复制。
- 基于长连接的命令传播:在完成全量复制后,长连接复制是主从库正常运行后的常规同步阶段。在这个阶段中,主从库之间通过命令传播实现同步。──注:传输的是命令,不是数据。
- 增量复制:在长连接复制阶段,如果遇到了网络断连,增量复制就派上用场了。──注:传输的是命令,不是数据。
注:在主从同步中,除了一开始是用 RDB 文件传输数据,之后都是传输操作命令的。
replication buffer
和 repl_backlog_buffer
都是存储的写操作命令。问题
为什么主从库间的复制不使用 AOF?
我的理解:AOF 的文件通常比 RDB 文件大,在网络传输中,耗时较大。其次,AOF 文件中存的是命令,还需要通过命令逐行恢复。