?在Redis中,可以通过slaveof
命令或者设置slaveof选项实现两台Redis服务器的主从复制,比如我们有两个Redis机器,地址分别是 127.0.0.1:6379 和 127.0.0.1:6380,现在我们在前者上面执行:
127.0.0.1:6379 > SLAVEOF 127.0.0.1:6380
?那么,127.0.0.1:6379就会成为从服务器,127.0.0.1:6380就是主服务器,主从服务器通过复制会保存相同的数据,这就是数据库状态一致。今天我们探讨的重点是,主从服务器之间是如何实现数据复制的,以及slaveof
这个命令的实现原理。
?主从复制的实现是通过两个操作来实现的,分别是同步(sync)和命令传播(propagate),我们看着这两个操作代表什么含义:
bgsave
命令,创建RDB文件;bgsave
命令执行期间处理的客户端新命令,并写入到某个缓冲区中;?主从复制分为初始化复制和断线后复制,即从服务器初始启动时,执行saveof
命令会执行一次同步,还有从服务器断线后再次链接,也会执行一次同步。
?在早起的Redis的版本中,无论是首次启动还是断线后重连,都是适用SYNC
命令实现,即:全量复制,但是SYNC
是一个特别耗费资源的操作,会占用大量CPU、内存、网络和磁盘I/O的资源,所以在后期的版本中,是使用增量复制PSYNC
来实现复制操作的。
?PSYNC
这个命令是同时具有完整同步和部分重同步的功能,其中完整同步的功能和SYNC
命令执行的步骤一样,而部分重同步的功能是在服务器断线重连后,如果条件允许,主服务器将断线期间的命令发送给从服务器执行,达到状态的同步的目的。所以这种部分重同步的操作相对于完整同步,是能减少很多资源消耗的。
?部分重同步的功能是通过3个部分构成的,分别是主从服务器两者的复制偏移量,主服务器的复制积压缓冲区,服务器的运行ID。
?复制的双方,分别会维护一个复制的偏移量:
?这样复制的双方就可以通过复制偏移量,达到同步的目的。如果主从服务器的状态一致,那么他们的复制偏移量总是相同的,否在是处于状态不一致的情况。
?复制积压缓冲区是由主服务器维护的一个固定长度先进先出的队列,默认大小是1MB。当服务器向从服务器传播命令时,它还会将此命令入队到复制积压缓冲区里面。同时,复制积压缓冲区会为入队的每一个字节
记录相应的复制偏移量值,这里的偏移量和2.1.1维护的偏移量值是相匹配。同时由于固定队列先进先出的特性,使得复制积压缓冲区中,仅保存最近一段时间执行的同步命令。
?当服务器连接到主服务器时,从服务器向主服务器发送PSYNC
命令是会带上自己的复制偏移量offset,主服务器根据此偏移量决定执行哪种操作:
?所谓的部分重同步操作,是指主服务器将从服务器偏移量offset之后的所有命令发给从服务器,避免全部命令重新发送的问题。
?每个Redis服务器(包括主从),都会有自己的运行ID,主从服务器首次进行同步时,主服务器会将自己的运行ID发送给从服务器,从服务器会保存此ID。
?当从服务器断线重连后,想要执行复制操作,会将前面保存的服务器ID发送给主服务器,此时由主服务器执行判断:
?在主从复制的命令传播期间,从服务器会以每秒一次的频率,向主服务器发送命令:
REPLCONF ACK <replication_offset>
?其中,replication_offset是服务器当前的复制偏移量。那么发送此命令的作用是什么呢,主要是下面三个:
# 从服务器的数量是3个
min-replicas-to-write 3
# 主从服务器之间的延迟时间,单位是3
min-replicas-max-lag 10