回答
单机版的 Redis 存在单点故障问题,Redis 的主从架构是 Redis 高可用和数据备份机制的核心。Redis 主从复制允许一个或多个从节点复制主节点的数据状态,其过程分为三个阶段:
1、建立连接阶段
这个阶段的主要作用是主从节点建立连接,为数据同步做准备。
- 保存主节点信息:当从节点执行
slaveof masterIp masterPort
命令后,就会将主节点的 IP、port 信息保存下来。 - 主从建立连接:从节点发现新的主节点后会尝试与主节点建立 Socket 连接。
- 发送 ping 命令:当主从建立连接后,从节点会向主节点发送
ping
命令,主要有两个目的:- 检查 Socket 连接是否可用
- 检查主节点是否可以处理请求
- 身份认证:如果主节点要求密码验证,从节点必须正确的密码才能通过验证。
2、数据同步阶段
当从节点发送 ping 命令收到 pong 回复后,主从节点就建立了连接,这时他们便可以进行数据同步了,具体的执行方式是:从节点向主节点发送 psync 命令,主节点根据当前状态的不同进行不同的复制流程。流程分为:全量复制和部分复制,下篇文章会专门介绍这两种复制方式,这里不再详述。
这里需要注意的两点:
- 主从首次建立连接时是进行全量复制,当主从断开连接,从节点重新连接时,则需要根据偏移量来判断是进行全量复制还是部分复制。
- 在数据同步前,从节点是主节点的客户端,主节点不是从节点的客户端,但是到了这个阶段以后,主从节点互为客户端,这是因为在这个阶段后,主节点会主动向从节点发送命令。
3、命令传播阶段
数据同步完成后,主节点会持续将新的写命令实时发送给从节点。这样就保证了主节点和从节点之间数据的实时一致性。
如果因网络等原因导致主从连接暂时中断,当重新建立连接时,通过 Redis 2.8 及以上版本引入的部分重新同步(PSYNC
)机制,从节点可以只请求丢失的数据,而不需要重新进行全量同步。
扩展
Redis 的主节点会根据当前状态的不同执行不同复制操作,包括全量复制和部分复制:
- 全量复制:用于首次复制或者其他不能进行部分复制的情况。全量复制是一个非常重的操作,一般我们都要规避它。
- 部分复制:用于从节点短暂中断的情况(网络中断、短暂的服务宕机)。部分复制是一个非常轻量级的操作,因为它只需要将中断期间的命令同步给从节点即可,相比于全量复制,它显得更加高效。
在 Redis 2.8 以前,从节点向主节点发送 sync
命令请求同步数据,此种方式是全量复制。在 Redis 2.8 以后,Redis 支持部分复制,发送的命令是 psync
。
全量复制
全量复制是指主节点将自身的整个数据集都发送给从节点的过程。因此它传输的数据量比较大,有一定的性能开销,所以我们需要尽可能地规避它。
- 如果从节点是第一次请求主节点数据,从节点是不会知道主节点的运行id(
runid
)的 ,所以从节点发送psync ? -1
。 - 主节点接收从节点的命令后,判定是进行全量复制,所以回复
+FULLRESYNC
,同时也会将自身的runid
和 偏移量 (offset
) 发送给从节点,响应为+FULLRESYNC {runid} {offset}
。 - 从节点接受主节点的响应后,保存主节点的
runid
和offset
。 - 主节点响应从节点请求后,执行
bgsave
,将生成的 RDB 文件保存在本地。 RDB
文件生成后,主节点会将它传输到从节点。从节点在接收到文件后,会加载这个RDB
到自己的数据库中,这个过程从节点会替换掉从节点上现有的所有数据。- 从节点加载
RDB
完成后,如果当前节点开启了AOF
,会立刻做bgrewriteaof
操作,为了保证全量同步后AOF
文件立即可用。 - 还有一点,从节点开始接收
RDB
文件到接收完成这段时间,主节点依然可以执行写请求,这个时候主节点是将这些请求写入到客户端缓冲区(repl_back_buffer
)。当从节点加载RDB
完成后,主节点会把缓冲区中的数据再发给从节点。
如下: