Redis的主从复制

Redis的主从复制

在Redis中,可以通过执行 SALVEOF 命令或者设置 slaveof 选项,让一个服务器去复制 (replicate)另一个服务器,在这里城被复制的服务器叫主服务器(master),而对主服务器进行复制的服务器则成为从服务器(slave)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
------复制开始------

127.0.0.1:12345> SLAVEOF 127.0.0.1:6379
OK

------复制完毕------

127.0.0.1:6379> SET msg "Hello World"
OK

127.0.0.1:6379> GET msg
Hello World

127.0.0.1:12345> GET msg
Hello World

------取消复制------
127.0.0.1:12345> slaveof no one
OK

主从复制的作用

  • 数据副本
  • 扩展读性能

执行流程

连接建立阶段

从节点通过 SALVEOF 命令发起连接,SALVEOF 命令是异步命令,从节点完成主节点ip和port的保存后,向发送slaveof命令的客户端直接返回 OK,实际的复制操作在这之后才开始进行。

数据同步阶段

主从节点建立连接后,开始数据同步,从节点向主节点发送 psync 命令开始同步,并且根据主从节点当前状态的不同,可以分为完整重同步和部分重同步。

copy.png

完整重同步

全量复制用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作。

从服务器对主服务器的同步操作需要通过向主服务器发送 PSYNC ? -1 命令来完成。

  • 从服务器向主服务器发送 PSYNC ? -1 命令,
  • 收到 PSYNC ? -1 命令的主服务器执行 BGSAVE 命令,在后台生成一个RDB文件,并使一个缓冲区记录从现在开始执行所有写命令。
  • 当主服务器的 BGSAVE 命令执行完毕时,主服务器会将 BGSAVE 命令生成的RDB文件发送给从服务器,从节点首先清除自己的旧数据,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行 BGSAVE 命令时的数据库状态。
  • 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。

copy2.png

部分重同步

部分重同步用户处理断线后重复制的情况:当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令就可以将数据库更新至主服务器当前所处的状态。

部分重同步分为主从服务器的复制偏移量、主服务器的复制积压缓冲区、服务器的运行ID三部分构成。

主从服务器的复制偏移量(replication offset)

执行复制的双方——主从服务器会分别维护一个复制偏移量

主服务器每次向从服务器传输N个字节的数据时,就将自己的复制偏移量加N。

从服务器每次收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加上N

通过对比主从服务器的复制偏移量,程序可以很容易地知道主从服务器是否处于一致状态:

  • 如果主从服务器处于一致状态,那么主从服务器两者偏移量总是相同的。
  • 相反,如果主从服务器两者的偏移量并不相同,那么说明主从服务器并未处于一致状态

copy3.png

主服务器的复制积压缓冲区(replication backlog)

复制积压缓冲区是由主服务器维护的一个固定长度先进先出队列,默认长度为1MB,当主节点开始有从节点时创建。

copy4.png

主服务器的复制积压缓冲区里面保存这一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录对应的复制偏移量。

当从服务器重新连上主服务器时,从服务器会通过 PSYNC 命令将自己的复制偏移量 offset发送给主服务器,主服务器会根据这个复制偏移量来决定从服务器执行何种重同步。

  • 如果offset之后的数据仍然存在与复制积压缓冲区,那么主服务器对从服务器发送 +CONTINUE 回复并执行部分复制。
  • 相反如果不存在,那么执行完整复制。
服务器的运行ID三部分构成(run ID)

每个Redis服务器,无论主从,都会有自己的run ID。
runID 在服务器启动时自动生成,由40个随机的十六进制字符组成。runid用来唯一识别一个Redis节点。主从节点初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来。

当从服务器断线并重新连上一个主服务器时,从服务器将向当前连接的主服务器发送之前保存的run ID:

  • 如果从服务器保存的run ID和当前连接的主服务器的run ID相同,那么说明从服务器断线之前复制的就是当前连接的这个主服务器,主服务器可以继续尝试执行部分重同步操作。
  • 如果不相同,那么说明从服务器断线之前的主服务器并不是当前连接的这个主服务器,主服务器将对从服务器执行完整重同步操作。

命令传播阶段

数据同步阶段完成后,主从节点进入命令传播阶段。在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。需要注意的是,命令传播是异步的过程,即主节点发送写命令后并不会等待从节点的回复,因此实际上主从节点之间很难保持实时的一致性,延迟在所难免。

参考资料

  • Redis设计与实现 黄健宏 机械工业出版社
  • Redis开发与运维 付磊 / 张益军 机械工业出版社