一、 概述
主从复制,是指将一台Redis服务器的数据复制到其他的Redis服务器。前者称为主节点(Master
/Leader
),后者称为从节点(Slave
/Follower
);数据是从主节点复制到从节点的。
其中,主节点负责写数据(当然有读的权限),从节点负责读数据(它没有写数据的权限)。
默认的配置下,每个Redis都是主节点。
一个主节点可以有多个从节点,但是一个从节点只能有一个主节点,即:主从节点是1对N的关系。如下图所示:
1.1> 主从复制的用处
(1)数据冗余:主从复制实现了数据的备份,实际上提供了数据冗余的实现方式。
(2)故障恢复:当主节点出现异常时,可以由从节点提供服务,实现快速的故障恢复,实际上提供了服务冗余的实现方式。
(3)负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器的负载
;在写少读多的业务场景下,通过多个从节点分担读负载,可以大大提高Redis服务器是并发量。
(4)高可用:哨兵配合主从复制,可以是实现Redis集群的高可用。
二、环境搭建
创建redis-cluster
目录,然后复制3份redis(也可以一个redis三份不同的配置文件,启动的时候,读取相应的配置文件),如下图所示:
分别修改它们的redis.conf配置文件,如下所示:
redis-6380/redis.conf
port 6380
pidfile /var/run/redis-6380.pid
logfile "redis-6380.log"
dbfilename dump-6380.rdb
daemonize yes
redis-6381/redis.conf
port 6381
pidfile /var/run/redis-6381.pid
logfile "redis-6381.log"
dbfilename dump-6381.rdb
daemonize yes
# 如果不通过修改配置文件,也可以在客户端中输入“SLAVEOF 127.0.0.1 6380”即刻生效!!
# 也可以在客户端中输入“SLAVEOF NO ONE”来断开主从关系
replicaof 127.0.0.1 6380
redis-6382/redis.conf
port 6382
pidfile /var/run/redis-6382.pid
logfile "redis-6382.log"
dbfilename dump-6382.rdb
daemonize yes
replicaof 127.0.0.1 6380
分别启动这3个redis服务:
开启3个客户端,来连接这3个redis服务实例;利用ping
查看服务是否正常,并且通过info replication
查看自己在集群中的角色
redis-6380
redis-6381
redis-6382
三、相关特性
3.1> 从节点是只读的
我们测试一下主节点redis-6380的读写操作,结果是读写都ok
我们测试一下从节点redis-6381的读写操作,发现不能执行写入操作,但是可以读取数据,其中muse是我们在6380主节点中添加的
我们测试一下从节点redis-6382的读写操作,也一样是只读的
3.2> 主节点意外宕机
我们关闭主节点6380的服务,查看从节点的对外服务是否收到影响
测试两个从节点是否可以对外正常的提供服务。如下所示,我们可以看到,从节点依然可以对外提供只读的服务
虽然主节点挂掉了,但是这两个从节点并不会自动的成为主节点,他们依然是从节点的角色。我们可以通过info replication
来确认一下
我们重新启动主节点,并且添加数据,我们来确认一下,这两个从节点会不会依然能够获得主节点同步过来的新数据
【解释】我们发现,两个从节点都可以获取到新添加的bob。说明,只要主节点再次成功启动,主从结构依然可以自动的建立起来。
四、实现原理
Redis的主从复制可以分为两个阶段:
- sync阶段
- command propagate阶段。
4.1> sync阶段
当从节点启动后,会发送sync
指令给主节点,要求全量同步数据。具体步骤如下图所示:
步骤1:Slave启动后,连接Master节点并发送sync指令。
步骤2:Master节点接到sync指令后,会执行BGSAVE
指令,生成RDB
文件。此外,在Master节点生成RDB文件时,会将此后客户端执行的增删改操作都存入缓冲区
。
步骤3:文件生成后,会发送给Slave节点,Slave节点接收到后,会删除所有旧的数据,然后加载RDB数据
,实现数据全量同步
操作。
步骤4:当Slave数据加载完毕后,Master会将缓冲区的指令
发送给Slave
步骤5:由Slave去执行缓冲区新增的指令
。
4.2> command propagate阶段
该阶段属于命令传播阶段。
上面我们介绍了,Slave节点通过sync指令请求Master节点全量数据的同步操作。那么,如果后续Master节点接收到新的增删改操作,也需要Slave节点接收同步的更新,那么这种就是command propagate
4.3> psync指令
当主从节点都正在运行的时候,出现了网络抖动,造成连接断开,那么当网络恢复,两个节点再次建立起连接的时候。从节点发送sync
指令后,主节点依然需要重新生成RDB,并对从节点进行全量数据的同步造成。那么这中间的耗时是非常严重的,并且传输备份文件也会对网络带宽造成很大的消耗。那么为了解决这个问题,从Redis 2.8开始,引入了psync指令来代替sync指令
psync指令会根据不同的情况,来确定执行全量重同步
还是部分重同步
全量重同步
- 当从节点是
第一次
与主节点建立连接的时候,那么就会执行全量重同步,这个同步过程与上面我们介绍的sync阶段
+command propagate阶段
一样
部分重同步
- 从节点的复制偏移量无法在复制积压缓冲区中找相应待同步的数据
- 主节点与从节点不是第一次同步(根据Redis节点ID判断)
什么是复制偏移量?
- Master节点和Slave节点都保存着一份赋值偏移量。
- 当Master节点每次向Slave节点发送n字节数据的时候,就会在Master节点偏移量加上n;而Slave节点每次接收到n个字节的时候,也会在Slave节点偏移量上加n。
- 在命令传播阶段,Slave节点会定期的发送心跳
REPLCONF ACK{offset}
指令,这里的offset就是Slave节点的offset。当Master节点接收到这个心跳指令后,会对比自己的offset和命令里的offset,如果发现有数据丢失,那么Master节点就会推送丢失的那段数据给Slave节点。如下图所示:
什么是复制积压缓冲区?
- 复制积压缓冲区是由主节点维护的一个固定长度(默认1MB)的队列。
- 它存储了每个字节值与对应的复制偏移量。
- 因为复制积压缓冲区的大小是固定的,所以它保存的是主节点近期执行的写命令。当从节点将offset发送给主节点后,主节点便会根据offset与复制积压缓冲区的大小来决定是否可以使用部分重同步。
如果offset之后的数据仍然在复制积压缓冲区内,则执行部分重同步;否则还是执行全量重同步
。
什么是节点ID?
- Redis节点服务启动之后,就会产生一个用来唯一标识Redis节点的ID。
- 当Master节点与Salve节点进行第一次连接同步的时候,Master节点会将ID发送给Slave节点,Slave节点接收到会,会对其进行保存。那么当主从服务之间发生了中断重连的时候,Slave服务器会将这个ID发送给Master服务器,Master服务器会拿自己的ID进行对比,如果相同,则说明主从之前是连接过的。否则,则说明是第一次建立的连接。那么,就需要全量去同步数据了。
今天的文章内容就这些了:
写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。
更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」