我们之前操作 Redis 都是单机版,但是实际应用中没人使用单机版,都是搭建集群的方式。这篇文章要介绍的主从复制,是指将一台 Redis 服务器的数据,复制到其他 Redis 服务器,我们将前者称为主节点 master,将后者称为从节点 slave(replica)。在这个过程中,数据的复制是单向的,即只能从主节点到从节点。并且从节点只能读数据,不能写数据,实现读写分离。
主从复制的优点
主从复制的前提就是多个 Redis 服务器,因此要多个配置文件。
开启主从复制的方式有两种:
配置配置文件
从服务器配置master节点
# 主节点ip port # replicaof <masterip> <masterport> # 主节点的认证密码(可选) # masterauth <master-password>
显示命令开启
客户端使用该命令slaveof [ip] [port]
INFO REPLLICATION
命令可查看节点信息
主从复制的实现可以分为三个阶段:建立连接、数据同步、命令传播
发送 slaveof 异步命令
建立 socket 连接
连接成功后从节点会为该 socket 建立一个专门处理复制工作的文件事件处理器,负责后续的复制工作,如接收 RDB 文件、接收命令传播等;
发送 ping 命令
从节点成为主节点的客户端之后,发送 ping 命令进行首次请求,目的是检查 socket 连接是否可用,以及主节点当前是否能够处理请求。
身份验证
取决于从节点是否设置 masterauth 选项,而这个又取决于主节点是否设置 requirepass
发送从节点端口信息
连接建立完成后,要进行主从数据库的数据同步,这一步也可以看作从节点中数据的初始化。数据同步有旧版和新版两种。我们先来看看旧版 Redis 怎么实现数据同步的
旧版同步使用的命令是 sync,同步方式是全量复制。以下是sync命令的执行步骤:
旧版同步功能的缺陷:
断线后重连需要再次发送 sync 同步命令,主服务再次生成 rgb 文件,从服务器载入恢复数据库状态。简单来说就是断线后又要全量复制,但其实没有必要,我们只需要同步断线后到重新连接期间主服务器变化的数据即可。
并且,sync是一个非常耗费资源的操作,因此旧版同步是非常低效的。
新版同步使用的命令是 psync ,同步方式是增量复制
psync 有完成重同步和部分重同步两种模式。完整重同步其实就是sync,主要用于处理初次服务的情况。部分重同步主要用于处理断线后重连的情况。部分重同步不需要重新生成、传送和载入整个rdb文件,只需要将从服务器缺少的写命令发送给从服务器执行即可。完美的解决了旧版同步效率低下的问题。
下面我们就来看看他是如何实现的?首先要了解几个概念
主节点和从节点的复制偏移量
主节点和从节点会各自维护一个复制偏移量 ( offset ),代表的是主节点向从节点传递的字节数。主节点每次向从节点传播 N 个字节数据时,主节点的 offset 增加 N;同理,当从节点每次收到主节点传来的 N 个字节数据时,从节点的 offset 增加 N。通过比较主节点和从节点的 offset 可以判断数据库状态是否一致,如果两者的 offset 相同,则一致,否则不一致;也可以根据两者的 offset 找出从节点缺少的数据。
主节点的复制积压缓冲区
主节点维护的一个固定长度的先进先出 ( FIFO) 队列,默认大小是 1MB。当主节点开始有从节点时,主节点创建复制积压缓冲区,其作用是备份主节点最近发送给从节点的数据。保存的数据有两方面:
- 最近传播的写命令。为什么最近呢?因为队列长度固定,老的命令会被新的取代
- 队列中每个字节对应的复制偏移量
当从服务器重新连接上主机时,会通过 psync 命令把自己的offset发给主节点
服务器的运行ID
每个redis服务器都有自己的运行ID,在启动时自动生成,由40个随机的十六进制字符组成
当从节点对主节点进行初次复制时,主节点会把自己的运行ID发给从节点,从节点保存并在断线重连上主节点时把次ID发送给主节点:
总结:psync的执行流程:
数据同步阶段完成后,主从节点进入命令传播阶段;在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。
这个阶段没啥可说的,就是把主节点执行的写命令发给从节点,让它们也执行一次,保证主从一致性
在命令传播阶段,从服务器默认会以每秒一次的频率向主服务器发送replconf ACK <replication_offset>
,其中replication_offset
是它当前的复制偏移量。心跳检测的目的有以下三个:
检测主从服务器的网络连接状态
如果主服务器超过一秒没有收到从服务的该命令,那么主服务器就知道主从连接出现问题了
辅助实现min-slaves
主服务我们可以配置以下两个参数来防止不安全写命令传播,如果从节点小于3或者lag大于10,主服务器都会拒绝执行写命令
# 从节点的最小个数 # min-replicas-to-write 3 # 从节点lag的最大值 # min-replicas-max-lag 10
检测命令丢失
上面说过心跳检测命令还发送了从节点自身保存的offset。主节点会与自己的 offset 进行对比,如果从节点数据缺失(如网络丢包),主节点会找到缺失的数据,并把这些数据重新推送给服务器(这里也会利用复制积压缓冲区)。
Redis设计与实现
Redis 进阶篇三——主从复制
Redis 主从复制