Redis 主从复制使用的是PSYNC
,PSYNC
命令具有完整重同步和部分重同步两种模式
- 完整重同步 用于处理初次复制情况:通过让主服务器创建并发送 RDB 文件,以及向从服务器发送保存在缓存区里面的命令来进行同步
- 部分重同步 用于处理断线后重复制情况:当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
部分重同步的实现原理
主服务器的复制偏移量和从服务器的复制偏移量
- 主服务器每次向从服务器传播 N 个字节的数据时,就将自己的复制偏移量的值加上 N
- 从服务器每次收到主服务器传来的 N 个字节的数据时,就将自己的复制偏移量的值加上 N
主服务器的复制积压缓冲区
-
前提
- 由主服务器维护的一个固定长度先进先出队列,默认大小为 1 MB。与普通的队列的区别:当入队元素的数量大于队列长度时,最先入队的元素会被弹出,而新元素会被放入队列
- 主服务器进行数据传播时,会将数据写入到复制积压缓冲区。
-
操作
- 如果 offset 偏移量之后的数据仍然存在于复制积压缓存区里面,那么主服务器将对从服务器执行部分重同步操作
- 如果 offset 偏移量之后的数据不存在于复制积压缓存区里面,那么主服务器器将对从服务器执行完全重同步操作
-
调整优化
复制积压缓冲区的最小大小的公式:
second * write_size_per_second
- second: 从服务器断线后重新连接上主服务器所需的平均时间
- write_size_per_second:主服务器每秒产生的写命令数据量
为了安全期间,一般设置为
2 * second * write_size_per_second
服务器的运行 ID
- 每个 Redis 服务器,不论主服务器还是从服务器,都会有自己的运行 ID。运行 ID 在服务器启动时自动生成,由 40 个随机的十六进制字符组成。
- 当从服务器对主服务器进行初次复制时,主服务器会将自己的运行 ID 传送给从数据器,从服务器会将这个 ID 保存起来。当从服务器断线并连接上一个主服务器时,从服务器将向当前连接的主服务器发送之前保存的运行 ID。
-
对复制方式的影响
- 如果从服务器保存的运行 ID 和当前连接的主服务器的运行 ID 相同,那么说明从服务器断线之前复制的就是当前连接的这个主服务器,主服务器可以继续尝试执行部分重同步操作
- 如果从服务器保存的运行 ID 和当前连接的主服务器的运行 ID 不同,那么说明从服务器断线之前复制的不是当前连接的这个主服务器,主服务器可以继续尝试执行完全重同步操作
PSYNC 命令
从服务器调用
-
如果从服务器以前没有复制过任何主服务器,或者之前执行过
SLAVEOF no one
命令, 那么从服务器在开始一次新的复制时将向主服务器发送PSYNC ? -1
的命令,主动请求主服务器进行完整重复制。 -
如果从服务复制过某个主服务器,那么从服务器在开始一次新的复制时将向主服务器发送
PSYNC <runid> <offset>
命令。- runid:上一次复制的主服务器的运行ID
- offset:从服务器当前的偏移量
主服务器回复
-
主服务器返回
+ FULLRESYNC <runid> <offset>
回复,那么表示主服务器将与从服务器执行完整重同步操作- runid:主服务器的运行ID,从服务器会进行保存
- offset:主服务器当前的偏移量,从服务器会将这个值作为自己的初始化偏移量
-
主服务器返回
+ CONTINUE
回复,那么表示主服务器将与从服务器执行部分重同步操作。从服务器只需要等待主服务器将自己缺少的部分发送过来 -
主服务器返回
-ERR
回复,那么表示主服务器的版本低于 Redis2.8,它识别不了PSYNC命令,从服务器发送SYNC命令,并与主服务器进行完全同步
复制的实现
通过向从服务器发送
SLAVEOF <master_ip> <master_port>
命令。
-
设置主服务器的地址和端口
-
建立套接字连接
-
发送ping命令
作用
- 检查套接字连接的读写状态是否正常
- 检查主服务器能否正常处理命令请求
结果
- 如果主服务器向从服务器返回一个命令回复,从服务器却不能在规定时限内读取出命令回复的内容,那么表示主从服务器网络连接不佳。当出现这种情况,从服务器断开并重新创建连向主服务器的套接字。
- 如果主服务器向从服务器返回一个错误,那么表明主服务器暂时没办法处理从服务器的命令请求。当出现这种情况,从服务器断开并重新创建连向主服务器的套接字。
- 如果从服务器读取到
PONG
,那么表明主从服务器之间网络连接正常,且主服务器可以正常处理从服务器的命令请求。
-
身份验证
-
发送端口信息
-
同步
在同步操作执行之前,总有从服务器是主服务器的客户端,但在执行同步操作之后,主服务器也会成为从服务器的客户端。
-
命令传播
心跳检查
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令 REPLCONF ACK <replication_offset>
. replication_offset 是从服务器当前的复制偏移量
-
检测主从服务器的网络连接状态
如果主服务器超过一秒钟没有送到从服务器发来的命令,那么主服务器器就知道主从服务器之间连接出现了问题
通过向主服务器发送
INFO replication
命令,查看lag
判断从服务器最后一次向主服务器发送命令的时间间隔 -
辅助实现 min-slaves 选项
Redis 的
min-slaves-to-write
和min-slaves-max-lag
两个选项可以防止主服务器在不安全的情况下执行写命令 -
检测命令丢失