主从模式

Redis 单机部署一般存在如下几个问题:

  1. 机器故障,导致 Redis 不可用,数据丢失
  2. 容量瓶颈:容量不能水平扩展
  3. QPS 瓶颈:一台机器的处理能力、网络宽带总是有限的,如果能够划分一些流量到其他机器,可以有效解决 QPS 问题

Redis 提供的主从复制功能,实现了一份数据存在多个相同的副本,它是实现 Redis 高可用的基础,作用有如下几个:

  • 数据冗余:主从复制实现了数据的热备份,是 Redis 持久化之外的一种数据冗余方式
  • 故障恢复:当主节点出现故障时,可以将从节点晋升为主节点继续提供服务,实现快速的故障恢复
  • 读写分离:主从复制可以实现读写分离,主节点写,从节点读,读写分离提高了服务器的负载能力
  • 高可用的基石:主从复制是哨兵和集群能够实施的基础,因此说主从复制是 Redis 高可用的基础

配置主从复制

默认情况下,Redis 所有节点都是主节点,节点与节点之间互不干涉,而参与主从复制的节点则是划分了主节点(master)和从节点(slave),它具有如下几个特点:

  1. 主节点下有一个或者多个从节点
  2. 每一个从节点只能有一个主节点
  3. 数据的复制是单向的,只能由主节点复制到从节点,所以我们不能在从节点上面执行写的操作

配置主从复制,只需要一个命令 slaveof ip port 即可,可以有三种方式

  1. 配置在配置文件中添加 slaveof ip port
  2. 在 redis-server 启动命令后增加 —slaveof ip port
  3. 直接使用命令 slaveof ip port

注意使用在从节点上面执行,ip 对应的是 masterIP,port 对应的也是 masterPort。下面来分析下主从复制的过程。
准备环境如下:

角色 IP port
master 127.0.0.1 6379
slave 127.0.0.1 6380

注:在生产环境中不推荐将主从服务器搭建在同一台服务器上面,这里是为了演示方便。

windows 启动redis-server不会选择当前文件夹配置的配置文件,可以

1
2
SH
redis-server.exe redis.windows.conf
  1. 启动 6379 、 6380 两台服务器,在 6380 上面执行 slaveof 127.0.0.1 6379
  2. 在 master 节点,执行命令 set test panther
  3. 在 slave 节点,执行命令 get test,得到的结果 panther,表名 master 数据已经同步到 slave 节点,主从部署完成。如下图

image-20231221172036068

主节点和从节点INFO信息

123

  • 主节点

connected_slaves:1 # 当前节点下存在一个从节定
slave0:ip=127.0.0.1,port=6380,state=online,offset=410,lag=1 # offset偏移量
master_repl_offset:410 # 主机点偏移量
repl_backlog_active:1 #是否开启复制缓冲区,1 表示已开启
repl_backlog_size:1048576 # 复制缓冲区的最大长度
repl_backlog_first_byte_offset:2 #起始偏移量,用于计算当前缓冲区可用范围
repl_backlog_histlen:409 # 已保存数据的有效长度

  • 从节点

role:slave # 角色为 slave 节点
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4 # 从节点超时时间 从网络断开到恢复后
master_sync_in_progress:0 # 数据同步状态,0 表示没有在进行数据同步
slave_repl_offset:522 # 偏移量
slave_priority:100 # 优先级
slave_read_only:1 # 从节点只读
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

原理

Redis 主从复制大体可以分为三个阶段:

  1. 建立连接阶段
  2. 数据同步阶段
  3. 命令传播阶段

建立连接阶段

该阶段的主要作用就是主从节点建立连接,为数据同步做准备。

1. 保存主节点信息

当从节点执行 slaveof masterIp masterPort 命令后,就会将主节点的IP、port 信息保存下来,这里需要注意的是 slaveof 是异步命令,它在保存主节点信息后立刻返回,实际的建立连接阶段是之后进行的。

2. 建立 socket 连接

从节点内部通过定时任务(每秒执行一次)维护着复制相关的逻辑,如果发现有了新的主节点,便会根据主节点的 IP 和 PORT ,创建 socket 连接,如果连接成功

3、发送 ping 命令

当主从节点建立连接后,从节点则就变成了主节点的一个客户端,这时从节点就会向主节点发送 PING 命令,发送该命令的目的有两个:

  1. 验证 socket 连接是否可用
  2. 判断主节点是否可以处理请求

从节点发送 ping 命令后,它可能会收到三个类型的回复:

  1. PONG:说明当前 socket 连接可用,且主节点可以处理请求,复制进程继续
  2. 超时:说明当前 socket 不可用,从节点则断开连接,重连
  3. 其他命令:如果主节点返回其他结果,说明主节点无法处理命令,当前可能正在处理其他超时运行的脚本,则从节点断开连接,重连

命令传播阶段

当主节点完成数据同步节点后,主节点已经将当前数据同步给从节点了,但是主节点还是在不断地接受命令,为了保证主从数据一致性,主节点需要持续不断地将写命令发送给从节点,需要注意的是,这个过程异步过程,即主节点发送写命令后并不会等待从节点的回复,因此主从节点之间的数据延迟是难免的,所以主从节点保证的是最终一致性。同时,主从之间的延迟与他们两者之间的网络状况、主节点写命令的执行频率、以及主节点中的 repl-disable-tcp-nodelay 配置等有关。

全量复制与部分复制

触发全量复制的条件

  • 第一次复制

由于是第一次进行数据同步,从节点并不知道主节点的 runid,所以发送 psync ? -1

image.png

  • 节点运行 ID 不匹配

我们将主机节点重启,主节点的ID会发送改变,这是从节点来复制数据就会触发全量复制

  • 复制偏移量 offset 不在复制积压缓冲区中

触发部分复制

当主从节点在命令传播节点发生了网络中断,出现数据丢失情况,则从节点会向主节点请求发送丢失的数据,如果请求的偏移量在复制积压缓冲区中,则主节点就将剩余的数据补发给从节点,保持主从节点数据一致,由于补发的数据一般都会比较小,所以开销相当于全量复制而言也会很小,流程如下:

image.png

  1. 由于主节点没有宕机,所以他依然会响应客户端命令,当然这些命令也不会丢失,都会存储在复制积压缓冲区中,默认 1MB。
  2. 当主从直接回复连接,从节点再次连接主节点