Redis主从复制搭建及原理

1 简介

1.1 Redis在单机、单节点、单实例下存在的问题

  • 单机故障
  • 内存容量有限
  • 访问压力
    Redis主从架构主要解决的问题:单机故障和访问压力,通过主从架构可以将访问流量分摊到多台服务器上,加上哨兵机制实现主从架构的高可用。主从架构将主节点数据复制到从节点即数据的冗余备份原理,所以不能解决内存容量的问题,内存容量可以通过Redis集群解决

1.2 主从架构概述

主从复制,是指将一台 Redis 服务器的数据(master 主节点),复制到其他的 Redis 服务器( slave 从节点),数据的复制是单向的,只能由主节点到从节点
默认情况下,每台 redis 服务器都是主节点,且一个主节点可以有多个从节点,但一个从节点只能有一个主节点。

1.3 主从复制作用

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式;
  2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  3. 负载均衡:在主从复制的基础上,配合读写分离,写数据时应用连接主节点,读数据时应用连接从节点,分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高 Redis 服务器的并发量。
  4. 高可用:主从复制是哨兵模式和集群能够实施的基础。

2 主从复制实现

2.1 环境准备

  1. CentOS7 3台
  • 192.168.88.110 端口6379 主机名q110(下面统一简称为主机名)
  • 192.168.88.111 端口6379 主机名q111(下面统一简称为主机名)
  • 192.168.88.112 端口6379 主机名q112(下面统一简称为主机名)
  1. Redis-6.2.6

2.2 网络拓扑图

2.3 Redis安装

3台服务器安装Redis6.2.6
官网
中文
Redis安装包解压完成后,详细安装目录可以查看README.md

# 1. 安装gcc
yum install gcc
# 2. 下载安装包
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
tar -xf redis-6.2.6.tar.gz
# 3. 编译 
cd redis-6.2.6 && make
cd src && make install PREFIX=/usr/local/redis
# 4. 配置环境变量
vi /etc/profile
# 添加环境变量
export REDIS_HOME=/usr/local/redis
export PATH=$PATH:$REDIS_HOME/bin

source /etc/profile
# 5. 根据Redis官方提供的脚本一键安装
cd ../../redis-6.2.6/utils
./install_server.sh

运行第5步报错,错误信息如下:

注释掉install_server.sh 中报错部分后重新执行install_server.sh

# 可执行多次。物理机中可以有多个Redis实例,通过port区分
./install_server.sh
# 根据提示内容按需修改,不修改直接回车确认

执行完成后redis实例默认已启动,配置及日志文件路径上图也有输出。

2.4 配置主从复制

从节点开启主从配置,有 3 种方式:

  1. 配置文件:在配置文件加入 slave < masterip > < masterport >
  2. 启动命令:redis-server 启动命令后加入 --slave < masterip > < masterport >
  3. 客户端命令:Redis 服务器启动后,直接通过客户端执行命令:slave < masterip > < masterport >

本文通过常用的配置文件加入。
Master节点修改配置:
修改/etc/redis/6379.conf 中的bind,默认只能本机访问,需添加2台salve 节点ip。
Slave节点修改:
修改q111和q112两台都需要修改

  1. 修改/etc/redis/6379.conf 中的bind,默认只能本机访问,需添加2台salve 节点ip。
    bind 192.168.88.100
  2. 配置主节点IP和端口
vi /etc/redis/6379.conf 
# 修改,如果主节点存在用户名和密码也需要配置上
replicaof 192.168.88.110 6379

重启3台从redis服务

systemctl restart redis_6379

验证
通过查看Master Redis日志可以看到已经将RDB同步到磁盘并发送给Salve节点。

查看Slave Redis日志可以看到已经从Master节点将RDB同步到磁盘

注意: Slave在同步Master节点RDB数据时会先删除自己的RDB文件。
通过客户端连接后在Master节点set 一个key 后 在Slave节点get 该key可以看到数据已经同步。
q112

q111

至此,主从复制已配置完毕。目前主从配置存在疑问:
当Slave down掉后,重新启动。是从Master从新拉全全量RDB还是增量数据?

3 主从数据同步原理

3.1 测试数据同步

3.1.1 Slave与Master首次建立主从

首次建立主从会全量同步。可查看2.4日志。

3.1.2 建立主从后Slave断开一段时间后重新启动

从上面2.4测试可以看到当Slave跟随Master时,会将RDB文件同步并清除自己所有数据,重新加载Master的RDB数据。我们可以在Slave已经与Master建立好主从关系后(数据已经同步)再将Slave关掉,在Slave关闭期间,往Master中添加数据,然后再重新启动Slave。
查看Slave启动日志:

查看RDB源文件

从Slave RDB源文件中可以看到,已经有保存repla-id 即MasterID。从日志中可以看到,当Slave在与Master已经建立主从关系情况下,宕机重启后并不会将Master数据全量同步,这与首次建立主从关系有不同。

3.1.3 测试AOF开启

上面的测试3.1.2 可以看出可能是因为RDB中已经存在了Master repla-id所有再次启动时不会全量同步。我们再测下将Slave开启AOF开启后,同样在关闭Slave期间Master增加数据后再启动Slave。

  1. 主机q112中执行
# 关闭Redis
systemctl stop redis_6379
# 修改配置
vi /etc/redis/6379.conf
# 开启AOF,配置文件中修改以下内容
appendonly yes

  1. Master中增加一些数据
  2. 重启Slave查看启动日志

通过日志中可以看在,在已经与Master建立了主从情况下并且开启AOF后,重新启动也会将全量数据同步到本地及内存。为了确实是否是第一次开启AOF才会全量同步,可以将此2.5.2实验再重试一次,得到的结论是一样的即:Redis主从中Slave开启AOF后每次重启会加载Master全量数据。里面具体原理是什么呢?

3.2 主从复制原理

3.2.1 数据同步原理

从节点通过发送psync命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制。

  • 全量复制:用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作。如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态;
  • 部分复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。需要注意的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制。

Redis使用一对Replicaion ID, offset来唯一识别Master节点数据集的版本,要理解这个“版本“的概念需要认识Redis的以下三个概念:

  • Replication ID(复制ID):每个Redis的主节点都用一个随机生成的字符串来表示在某一时刻其内部存储数据的状态,“某一时刻”可以理解为其成为master角色的那一刻,由源码可知在第一个从节点加入时,Redis初始化了复制ID。
  • offset(复制偏移量):主从模式下,主节点会持续不断的向从节点传播引起数据集更改的命令,offset所表示的是主节点向从节点传递命令字节总数。它不是孤立存在的,需要配合复制积压缓冲区才能工作。
  • backlog(复制积压缓冲区):它是一个环形缓冲区,用来存储主节点向从节点传递的命令,它的大小是固定的,可存储的命令有限,超出部分将会被删除。它即可用于部分同步,也可用于命令传播阶段的命令重推。

上图说明:

  • 图示Redis角色为Master,其复制ID(replid)为xxxx,当前的复制偏移量(offset)为1010;
  • 它有一个复制积压缓冲区(backlog),容量(backlog_size)为100,backlog起点相对于offset的偏移量(backlog_off)为1000,当前backlog存储的命令字节数(backlog_hislen)为11个,对应了backlog中【1000,1010】偏移量范围内的字节;
  • offset始终与backlog中最后一个字节的偏移量相同。
    上图分析:
  • Redis-1:replid和offset为默认值,说明它从未与主节点进行过同步操作,所以是进行全量同步;
  • Redis-2:replid主从节点一致,slave_offset>=backlog_off并且slave_offset<offset,说明该从节点丢失的数据可以通过复制积压缓冲区找回,所以可以进行部分同步;
  • Redis-3:replid主从节点一致,slave_offset<backlog_off,说明该节点丢失的数据过多,通过复制积压缓冲区无法找回,所以是进行全量同步;
  • Redis-4:replid主从节点一致,之前不是与当前节点进行主从复制,所以是进行全量同步;
    总结:部分同步其实是以全量同步为基础(得到复制ID),用复制积压缓冲区中的缓存命令做命令重放的增量同步逻辑,不过受制于复制积压缓冲区的容量,它可容忍的范围是有限的。这与持久化机制的AOF混合持久化如出一辙,也与mysql中主从复制的Binlog思路不谋而合。

3.2.2 命令的执行

Master-Slave建立主从关系后,当Master执行完写操作命令后,会通过psync把写命令追加至复制积压缓冲区,然后异步地发送给slave。slave接收命令并执行,同时更新slave维护的复制偏移量offset。

复制积压缓冲区是由主节点维护的、固定长度的、先进先出(FIFO)队列,默认大小1MB(通过配置repl-backlog-size)。例如如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(特定协议格式)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。
从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制:

  • 如果offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部分复制;
  • 如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制。
posted @ 2022-02-26 17:01  Dvomu  阅读(891)  评论(0编辑  收藏  举报