4 redis复制

4.1 背景

为了解决redis单点数据问题,通常会把数据复制多个副本部署到其他机器上,满足了故障恢复和负载均衡等需求。

参与复制的redis实例分为主节点(master)和从节点(slave), 默认情况下redis都是主节点,主节点可以有多个从节点, 从节点只能有一个主节点,且数据的复制流向是从主节点到从节点单向流动。

4.2 配置

4.2.1 建立复制

复制的方式有3种:

1 配置文件:
在从节点配置文件中加入 slaveof {masterHost} {masterPort} 随redis启动生效;

2 启动配置:
在redis-server 启动命令后加入 --slaveof {masterHost} {masterPort}

3 运行期间动态配置:
直接使用命令 slaveof {masterHost} {masterPort} 生效;

4.2.2 取消复制

取消复制有2种方式:

1 从节点执行 slaveof no one 来断开与主节点的复制关系;

2 从节点执行 slaveof {newMasterHost}{newMasterPort} 来切换当前主节点为newMaster新的主节点

4.2.3 安全性

对一些主节点数据要求比较严格, 可以在主节点设置requirepass参数来进行密码验证,这时需要客户端通过auth命令进行校验,从节点在连接的时候,需要配置中新加masterauth参数且需要与主节点密码一致才能建立复制关系。

4.2.4 从节点只读

默认情况下从节点是只读模式,使用slave-read-only=yes 默认配置成只读模式。

由于复制的数据流向只能从主节点到从节点,如果从节点有写操作,会导致主从节点数据不一致。

4.3 拓扑

redis的复制拓扑结构可以支持单层或多层复制关系,分为:一主一从、一主多从、树状主从结构。

1 一主一从

适应场景:
当应用写并发量较大且需要持久化时,可以在从节点开启AOF.这样既保证了主节点的性能,也可以对数据进行持久化操作。

4 redis复制
注意点:
当主节点突然宕机重启时,需要使用哨兵进行重新选举。 如果主节点重启后仍然是主节点,因主节点之前没有开启持久化功能,重启会清空数据,从节点从主节点复制数据也会清空数据, 所以主节点重启后最好根据哨兵选举来决定主从关系。

2 一主多从

适用场景:
对于读占比较大的场景,应用端利用多个从节点实现读写分离。
4 redis复制

注意点:
对于写并发量较大的场景不适用,多个从节点都会从主节点复制数据,会消耗大量网络带宽,同时也加剧了主节点的负载,影响服务稳定性。

3 树状主从

适用场景:
和一主多从相比, 引入复制中间层,有效降低了主节点的负载和需要传输数据从节点的数量。

4 redis复制

总结

当写并发量较大,使用一主一从;
当读操作较大,使用一主多从,进行读写分离;
如果一主多从中写并发量也很大,可以考虑使用树状主从结构,降低主节点的负载和从节点的数量。

4.4 原理

4.4.1 复制过程

当从节点执行slaveof之后,就开始进行和主节点的复制过程,如下:

1)从节点先保存主节点的信息,可以通过info replication来查看

2)从节点内部会通过每秒执行的定时任务维护复制相关逻辑,当定时任务发现新的主节点后,会尝试与主节点进行网络连接,建立socket连接;

如果从节点没有连接到主节点,定时任务会无限次重试直到连接成功为止。

3)连接建立成功后,从节点会向主节点发送 ping命令,检测网络是否连通;

4)如果主节点设置了requirepass,从节点还需要进行密码验证;

5)首次数据同步,主节点会全量复制,把所有的数据发送给子节点,如果数据量较大会非常耗时间;

6)1-5完成后就已经建立好和主节点的复制关系,后续从节点的定时任务每秒去主节点同步增量数据;
4 redis复制

4.4.2 数据同步

redis 2.8 以上版本使用psync 命令来完成主从数据同步,同步过程分为:全量复制、部分复制。

全量复制: 首次与主节点建立连接,需要全量复制数据,发送给子节点,如果数据量较大会造成网络开销, 建议在低峰时操作;

部分复制: 主从复制过程中因网络中断等原因造成的数据丢失场景,当从节点再次连接上主节点后,对丢失的数据进行补发。因补发的数据远小于全量,可以避免全量复制的高开销。

psyc命令需要以下组件支持:
1 复制偏移量

参与复制的主从节点都会维护自身的复制偏移量, 通过对比主从节点复制偏移量可以判断是否数据一致性,缺失的话, 主节点会发从缺失的数据给从节点

2 主节点运行ID
每个主节点在运行的时候ID都不同,从节点也是根据主节点运行时ID来识别自己复制的是哪个主节点。

3 psync命令
从节点使用 psync {runId} {offset} 来完成部分复制和全量复制功能。
runId: 从节点对应复制的主节点运行时ID
offset: 当前从节点已复制的复制偏移量

psync流程说明:
1) 从节点向主节点发送 psync命令, runId是主节点的运行时id, 如果没有默认是? , 参数offset是当前从节点已复制的复制偏移量,如果是首次复制默认值为 -1;

2)主节点根据psync参数来决定响应结果:
FULRESYNC 表示全量复制;
CONTINUE 表示部分复制;
ERR 说明主节点版本低于2.8 无法识别psync命令, 从节点会发送旧版本的sync 命令进行全量复制。

4 redis复制

4.4.3 全量复制

从节点首次与主节点建立复制关系时,必须经历全量复制过程, 过程如下:

1)从节点发送 psync 命令给主节点;
2)主节点会根据 psync参数, 且因为是首次建立复制, 会返回FULLRESYNC响应;
3)从节点保存主节点的信息,包括runId offset
4)主节点调用bgsave 命令生成rdb持久化文件;
5)主节点发送步骤4生成的rdb文件给从节点;
6) 首次发送的rdb文件一般比较大,在发送过程主节点接受的写命令会写入到缓冲区, 当步骤5发送完成后,会把缓冲区的数据也发送给从节点,保证主从数据的一致性;
7)从节点需要清空本地的旧数据;
8) 把从主节点接受的rdb文件加载到本地
9)如果从节点开启了aof, 会立刻执行 bgrewriteof操作进行重写。
4 redis复制

4.4.4 部分复制

部分复制的流程和全量复制类似,区别是主节点只会把子节点缺失的数据发送给从节点, 主要是从主节点的复制积压缓冲区中的数据进行部分复制,如果复制的数据不在缓冲区会变成全量复制。
4 redis复制

4.4.5 心跳

主从节点建立复制后,会彼此维护长连接并发送心跳命令, 主从心跳机制:

1) 主节点默认每10s 对从节点发送 ping命令, 检测从节点的存活性和连接状态;

2) 从节点每秒会向主节点发送 replconf ack {offset} 命令,给主节点上报自身当前的复制偏移量, 检测数据是否丢失,如果从节点数据丢失,再从主节点的复制缓冲区拉取丢失的数据。
4 redis复制