Redis 主从复制技术:理论基础、运行逻辑与应用场景

在当今数字化时代,数据量呈爆炸式增长,对于应用程序而言,保障数据的高可用性和高性能变得至关重要。在众多的解决方案中,Redis凭借其丰富的特性脱颖而出,而主从复制便是其中一项关键技术。

想象一下,一个大型电商平台在促销活动期间,海量的用户请求如潮水般涌来。此时,单一的Redis实例很难应对如此巨大的流量压力,而且一旦出现故障,整个系统可能会陷入瘫痪。Redis主从复制机制就如同为系统搭建了一道坚固的防线,通过复制主节点的数据到多个从节点,不仅提升了系统的读取性能,还增强了数据的可靠性。

Redis主从复制是如何巧妙地实现数据同步的?在实际应用中又该如何进行配置和管理?不同节点之间的角色是如何协同工作的?接下来,就让我们一同深入Redis主从复制的世界,揭开其神秘的面纱,探寻其中的奥秘。

一、详解Redis主从复制

1. 主从复制的基本概念

主从复制就是将主节点(master)的数据复制到从节点(slave),让多个节点承载用户的请求:

主从复制具备以下几个特点:

数据冗余:主节点的数据都会同步到从节点上,所以多个节点都会有相同数据,从而实现数据冗余。故障恢复:主节点出现故障后,从节点可以继续承载用户的请求,做到服务上的冗余。负载均衡:主从复制机制实现主节点接收用户写请求,从节点承载用户读请求,对于读多写少的场景,这种机制可以大大提高redis的并发量。高负载:主从复制+哨兵机制可以实现高负载,这点后文会介绍到。2. 主从复制使用示例

首先我们先来介绍一下一主二从,即搭建一个主节点和两个从节点,主节点负责写入请求,从节点同步数据对外提供数据读服务:

创建3个redis配置文件,以笔者为例,名字分别为redis6379.conf、redis6380.conf、redis6381.conf,同时我们将6379这个端口号的redis作为主节点,配置内容如下:

复制
# 引入redis基本配置,注意这个配置只支持RDB include /root/redis/redis.conf pidfile /var/run/redis_6379.pid port 6379 # 设置RDB文件名 dbfilename dump6379.rdb1.2.3.4.5.6.

从节点以6380,配置如下:

复制
# 引入redis基本配置,注意这个配置只支持RDB include /root/redis/redis.conf pidfile /var/run/redis_6380.pid port 6380 dbfilename dump6380.rdb # 作为6379的主节点 slaveof 127.0.0.1 63791.2.3.4.5.6.7.

分别启动这几个redis:

复制
redis-server /root/redis/conf/redis6379.conf redis-server /root/redis/conf/redis6380.conf redis-server /root/redis/conf/redis6381.conf1.2.3.

完成配置后,我们就可以开始测试了,首先对清空主节点数据,并设置一些值进去:

复制
127.0.0.1:6379> flushdb OK 127.0.0.1:6379> set master_key value OK 127.0.0.1:6379>1.2.3.4.5.

我们看看从节点是否存在这个key值,可以发现这个值确实存在。

复制
# 可以看到主节点的key来了 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli -p 6380 127.0.0.1:6380> keys * 1) "master_key" 127.0.0.1:6380>1.2.3.4.5.

再使用命令看看6380,发现其角色也确实是从节点:

复制
127.0.0.1:6380> info replication # Replication role:slave master_host:127.0.0.1 master_port:6379 .... 略1.2.3.4.5.6.
3. 演示主从复制运行时异常

从节点挂掉,在启动,数据不会丢失,照样是主节点的从节点,这个点我们也可以拿个例子来展示一下,首先我们可以将从节点挂掉:

复制
# 强制挂掉从节点 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli -p 6380 127.0.0.1:6380> SHUTDOWN not connected>1.2.3.4.

清空数据主节点设置一些新数据,再次启动从节点,可以发现它还是从节点的角色:

复制
# 启动 发现数据都在,并且角色也是slave [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-server /root/redis/conf/redis6380.conf [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli -p 6380 127.0.0.1:6380> info replication # Replication role:slave .....略1.2.3.4.5.6.7.

主节点挂了,从节点仍然是从节点,主节点恢复后仍然是主节点。

这个例子,首先我们也是需要将主节点挂掉:

复制
# 强制挂掉主节点 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli 127.0.0.1:6379> SHUTDOWN not connected>1.2.3.4.

完成后再次将主节点启动,然后进行操作,发现角色仍然是master,而且进行各种set操作80这个从节点也会同步复制。

复制
# 再次启动主节点,发现key都在并且角色仍然是master,设置一个k2值 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-server /root/redis/conf/redis6379.conf [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli 127.0.0.1:6379> set key2 v2 OK 127.0.0.1:6379> # 从节点仍然可以收到,说明主节点仍然是6379 [root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli -p 6380 127.0.0.1:6380> keys * 1) "key2" 2) "master_key" 127.0.0.1:6380>1.2.3.4.5.6.7.8.9.10.11.12.13.
4. 主从复制下的薪火相传

如果大量主节点配合大量从节点,会导致主节点会导致数据同步时长增加,所以我们可以将部分从节点挂到某部分从节点下面,以此类推,作为从节点的从节点:

以笔者本次示例为例,我们将81作为80的从节点:

复制
# 为了方便,笔者使用命令的形式,读者也可以使用conf文件配置 127.0.0.1:6381> SLAVEOF 127.0.0.1 6380 OK 127.0.0.1:6381>1.2.3.4.

再次查看80节点,可以看到slave0:ip=127.0.0.1,port=6381,state=online,offset=810,lag=1,由此可知从节点的从节点配置完成:

复制
[root@iZ8vb7bhe4b8nhhhpavhwpZ sbin]# redis-cli -p 6380 127.0.0.1:6380> info replication # Replication role:slave # 6381变为它的从节点 slave0:ip=127.0.0.1,port=6381,state=online,offset=810,lag=11.2.3.4.5.6.
5. 反客为主

对着从节点键入下面在这段命令,即直接让从节点停止复制并直接晋升为主节点:

复制
slaveof no one1.

二、、主从复制进阶知识点

1. 主从复制的原理

主从复制有两种模式,我就先来说说全量复制吧,如下图,整体步骤为:

从节点向主节点发送同步请求,因为不知道主库的runID,并且不知道同步的偏移量是多少,所以参数分别为? -1,同步请求的指令为psync主库执行bgsave指令生成rdb指令,将数据发送给从库,从库为了保证数据一致性,会将数据清空,然后加载rdb文件,完成数据同步。在此期间,主库收到的新数据都会被存入replication buffer中。主库会将replication buffer发送给从库,完成最新数据的同步。

从 Redis 2.8 开始,因为网络断开导致数据同步中断的情况,会采用增量复制的方式完成数据补充。

需要了解的是,当主从同步过程中因为网络等问题发生中断,repl_backlog_buffer会保存两者之间差异的数据,如果从库长时间没有恢复,很可能出现该环形缓冲区数据被覆盖进而出现增量复制失败,只能通过全量复制的方式实现数据同步。

需要一个概念replication buffer,这个缓冲区用于存放用户写入的新指令,完成全量复制之后的数据都是通过这个buffer的数据传输实现数据增量同步。

2. 主服务器不进行持久化复制存在什么问题

设想下面这样一个场景,主节点没有使用RDB持久化,数据没有持久化到磁盘,在此期间主节点挂掉又立刻恢复了,此时主节点所有数据都丢失了,从节点很可能会因此清空原本数据进而导致数据丢失。

3. 为什么主从复制使用RDB而不是AOF

RDB是二进制且压缩过的文件,传输速度以及加载速度都远远快速AOF。且AOF存的都是指令非常耗费磁盘空间,加载时都是重放每个写命令,非常耗时。需要注意的是RDB是按照时间间隔进行持久化,对于数据不敏感的场景我们还是建议使用RDB。

4. 什么是无磁盘复制模式

数据同步不经过主进程以及硬盘,直接创建一个新进程dump RDB数据到从节点。对于磁盘性能较差的服务器可以使用这种方式。配置参数为:

复制
repl-diskless-sync no # 决定是否开启无磁盘复制模式 repl-diskless-sync-delay 5 # 决定同步的时间间隔1.2.
5. 为什么会有从库的从库设计

由上可知,主库执行数据同步时,需要执行如下步骤:

生成rdb文件。传输数据给从库。

为避免主库因为频繁为大量从库做同步导致性能下降,于是我们才引入从库的从库这一设计方案分散同步压力:

6. 读写分离及其中的问题

大抵需要考虑以下这些问题:

延迟与不一致问题:如果对数据一致性容忍度较低,网络延迟导致数据不一致问题只能通过提高网络带宽,或者通知应用不在通过该节点获取数据数据过期问题,从节点很可能在某一时刻某些过期数据被读取到了,这就会给用户造成很诡异的场景。故障切换问题7. 如果在网络断开期间,repl_backlog_buffer 环形缓冲区写满之后,是进行全量还是增量复制

针对这个问题我们必须要了解repl_backlog_buffer是什么,它是redis主从同步时master的一个环形缓冲区,在master节点同步指令给slave时,这个缓冲区也会临时缓冲这部分数据以保证slave断线重连后的数据补偿,针对该问题,我们需要分两种情况说:

若主库的repl_backlog_buffer的slave_repl_offset已经被覆盖,那么同步就需要全量复制了从库会通过psync命令把自己记录的slave_repl_offset发给主库,主库根据复制进度决定是增量复制还是全量复制。8. 1主2从redis架构如何抗住1000w的qps

结合redis官方给出压测报告来看,redis的qps基本在8w~15w这个区间,所以如果需要应对1000w的qps我们就需要考虑水平复制数据并拓展,按照压测的情况并结合只需要抗住qps的需求,我们可以得出第一个方案——通过薪火相传的架构来保证数据同步。

按照单机10w的qps来换算,我们可以通过100个redis节点搭建一个薪火相传的架构抗住并发压力:

当然考虑到100个节点的成本可能不切实际,所以我们也可以采取另一套相对折中的方案,结合服务器资源部署一套redis主从架构+哨兵架构保证高可用,然后各个服务模块基于本地内存到redis中同步热点数据,让应用直接对外提供缓存数据检索,由此节约了资源成本还间接的减小的接口响应的RT:

阅读剩余
THE END