单机服务部署架构在目前的互联网时代应该很少见了,单机服务有一个非常大的隐患就是当服务机器出现故障的时候,如果短时间不能修复就意味着线上会持续无法正常提供服务,那主从结构的出现最直接的目的就是为了解决这样的问题,提高服务的高可用性,除此之外其实主从结构的设计还可以起到负载均衡的作用,就拿redis来说,普通中小企业一些互联网产品的客户量以及服务并发请求量并不是特别大,单机架构在排除出现故障的可能性之后足以支撑所有业务的请求负载,但是在现今互联网大厂中如果采用单机的redis服务肯定是无法承载非常高并发的业务规模,那这个时候用主从结构的读写分离方式就可以起到分散降低大客户量高并发场景下给系统带来的压力,当然互联网大厂还有分布式架构设计,这个我们后面介绍redis分布式文章的时候会介绍。我们带着这些认知开始这篇文章的学习。

前言

       施主,既然来了,就静下心来,仔细阅读好好思考!        老衲才疏学浅,如有错误,还请各位大侠在评论区不吝赐教。

正文

一、什么是主从结构

一主一从和一主多从的结构,到底如何设计还得根据实际的生产环境考虑,我们画图来理解一下主从结构:

redis主从架构为什么至少3台机子 redis主从结构_Redis主从结构

主从结构中没有要求说固定哪台服务器一定要是master哪些机器是slave,但是为了保证主从结构中所有服务的数据一致性,规定master用来进行数据的读写操作,slave提供只读数据操作,另外数据的同步方向是master到slave单向同步,这样就能保证在主从结构中更新数据都统一在一台服务中进行,然后所有机器的数据同步只需要从master到其他slave,这样就能够保证数据一致性,我们简单总结一下:

  1. 一个master可以有多个slave
  2. 一个salve只能有一个master
  3. 数据同步的流向必须是单向的从master到slave

主从服务之间的数据同步我们称为主从复制,在搭建主从架构的时候,我们新建一个slave节点也就意味着要进行从master数据同步到slave的过程,这就是我们接下来要讲的内容。

二、Redis主从结构的实现:主从复制

       主从结构的实现过程中,最复杂的就是主从服务间的数据同步等一些列相关操作,redis主从结构的实现有两种方式,分别slaveof命令和配置文件的方式,我们只需要通过这两种方式的一种就可以轻松构建主从结构,redis替我们封装了具体的数据同步相关的复杂操作,关于底层同步数据时的主从复制相关内容,我们在本章后面内容讲解,这里我先介绍如何使用这两种方式。

(1)方式一:slaveof命令

slaveof ip port命令即可,其中ip和端口指master的,我们来看下运行流程图:

redis主从架构为什么至少3台机子 redis主从结构_redis主从数据同步方式_02

其中客户端执行了slaveof命令之后,redis会立刻异步给客户端一个ok响应,但在redis当中还需要经过一些列复制相关的过程,比如主从服务的连接、连接之后再是从master将数据全量同步复制到新增的这个slave节点中等操作。

实操:

       由于资源有限,我在同一台机器里面启动两个redis服务,下载的windows版本的,分别解压在两个目录中,之所以解压到两个目录下是因为我在一个目录下尝试启动两个redis服务时并且同时用两个cmd窗口连接这两个服务后,在操作的过程中老是会有一方卡主不动,不知道是不是windows环境的原因,在linux环境下我还没试过。主节点我是通过默认的方式启动的,从节点的服务我是通过带配置文件的启动方式启动的redis-server configPath(配置文件路径),生成一个自定义配置文件,自定义配置文件中的port参数修改为6380,相关命令可以看我的文章Redis基础:一文学会从安装到使用,两个redis服务启动的端口分别是6379和6380,master所在的节点是端口为6379的服务,并且执行了set hello world命令,另外一个就是从节点,来看下我在从节点执行slaveof命令的前后:

redis主从架构为什么至少3台机子 redis主从结构_Redis主从复制_03

可以看到在成为从节点之前,获取hello的值是不存在的,执行主从复制之后,再执行命令就可以取到master同步过来的缓存数据了。另外如果某台机器不想成为从节点只需要在该redis服务执行命令slaveof no one命令即可,这样slave节点就和master节点断开链接:

redis主从架构为什么至少3台机子 redis主从结构_Redis主从复制_04

看到没有,我们执行了slaveof no one之后,在尝试查询hello的值还是存在的,说明执行这个命令后redis不会立即清空当前已缓存的数据,那什么时候才会清空呢?我们试下此时把6379的hello删除掉,然后重新将6380设置为6379的从节点再查询看看结果:

redis主从架构为什么至少3台机子 redis主从结构_Redis面试题 _05

从结果可以看出在成为从节点的时候会先清空目前缓存的数据。我们另外来尝试下6380这个从节点是否可以进行写数据:

redis主从架构为什么至少3台机子 redis主从结构_redis主从架构为什么至少3台机子_06

可以看到redis在执行slaveof命令之后,自动帮我们将新加入的从节点设置为只读的操作权限,如果通过下面的配置形式,需要手动配置为只读。

(2)方式二:配置文件方式

       前面介绍redis的两种持久化方式中也有配置的方式,同样redis构建主从结构也可以通过配置的方式实现,我们来看下在配置文件中涉及到的配置项:

  • slaveof ip port:和命令的方式一样,指定为哪个master的从节点;
  • slave-read-only:配置为yes,固定slave节点只可以进行读操作,这样就能保证只有master进行写操作;
  • masterauth:如果主节点有密码的话需要在这里配置密码。

       这里就贴出三个相关的配置项,其实还有很多大家可以打开配置文件详细看看。通过配置的方式需要对节点进行重启操作,而不像命令的方式,执行运行即可。可以看到redis实现主从结构还是非常简单方便的,主从结构中复制的数据同步相关操作都在redis内部封装实现了,我们不用过多的关心这一块内容。

实操:

       首先我们更改从节点6380的配置文件:

redis主从架构为什么至少3台机子 redis主从结构_Redis主从结构_07

redis主从架构为什么至少3台机子 redis主从结构_redis主从架构为什么至少3台机子_08

默认情况下slaveof在配置文件中是被注释掉的,这里我们加进来,slave-read-only默认就是打开并且值为yes,然后我们来进行带配置文件的启动方式启动:

redis主从架构为什么至少3台机子 redis主从结构_redis主从架构为什么至少3台机子_09

redis主从架构为什么至少3台机子 redis主从结构_Redis面试题 _10

我们修改配置文件重新启动之后get key1就有来之master节点的数据了,可以通过命令:info replication来查看当前redis服务的状态,我们分别看下master和slave:

redis主从架构为什么至少3台机子 redis主从结构_redis主从架构为什么至少3台机子_11

redis主从架构为什么至少3台机子 redis主从结构_Redis主从复制_12

这个命令可以查看服务节点的状态信息,主节点记录了从节点的个数等信息,从节点记录了主节点的相关信息,这里我不一个个介绍每个数据项代表的是什么了,其实每个数据项的名称已经很直观的可以看出来了,比如master_link_status:up表示的是目前和master节点的连接状态,如果我们关闭master节点服务,在从节点执行info replication会看到该数据项的值为down。配置方式下启动的redis服务,也是可以执行slaveof no one命令,如果重启之前配置文件没修改的话同样会将6379作为主节点。

三、主从复制底层细讲

全量复制和部分复制,在介绍这两种复制的具体流程和触发时机时我们先得知道三个相关概念:run_id、主从复制偏移量和主从复制积压缓冲区。

run_id:每次redis服务重新启动的时候都会生成一个新的唯一的run_id,类似当前运行的redis服务的身份标识,可以通过命令info server查看当前redis服务的run_id;

主从复制偏移量:在主从结构中master和slave的对这个字段的命名有点差异,可以通过info replication命令查看,master节点有字节输出就会不断增加复制偏移量,在部分复制时这是一个关键参考值;

主从复制积压缓冲区:维护在master中一个FIFO队列。在master每次向外传输时,也会向该队列中传输。该队列中会有对应的偏移量和其对应的字节记录,部分复制的内容就是从这里面同步到从节点的。

现在来看全量复制和部分复制的触发时机和具体流程,在redis主从结构中,slave同步master数据是通过请求master执行psync完成的主从数据同步。从节点初次执行slaveof命令的时候,肯定需要进行全量复制过程的,我们看看全量复制的过程:

redis主从架构为什么至少3台机子 redis主从结构_redis主从架构为什么至少3台机子_13

当我们在从节点执行slaveof命令后,redis内部就启动上面的操作:

  • 1. slave节点初次请求psync命令,此时从节点是没有保存过master的runid和对应的复制偏移量;
  • 2. master节点接收到psync请求,发现没有runid和offset说明需要全量复制数据,此时响应给slave节点进行全量复制标识并携带自己的runid和当前的复制偏移量给到slave;
  • 3. slave接收到全量复制的标示之后保存master的runid和offset信息;
  • 4. 因为需要全量复制,所以master节点进行异步RDB持久化方式生成RDB文件(关于持久化可以看我相应文章);
  • 5. master持久化RDB文件生成后发送给slave节点,从节点接收并且将RDB保存在本地,后续作为数据的来源;
  • 6. master在给slave发送RDB文件到slave接收完成的整个期间,master是正常接收客户端的相关请求的,这时候如果master有新的更新的话会把更新数据记录在复制积压缓冲区,待从节点加载RDB完成后,再将缓冲区的变更数据发送给从节点进行同步;
  • 7. slave节点拿到master的同步数据后,先是情况当前缓存的数据;
  • 8. slave清空缓存的数据后开始加载master同步过来的数据。

全量复制流程已经知道了,我们来分析一下全量复制这个过程为什么非常耗时。

从master节点分析:我在将redis持久化的文章里面说过。如果生产环境上的缓存数据量非常大,那么进行rdb持久化是一个非常耗时的操作,尽管是通过异步的bgsave操作,而且除此之外我们将一个比较大的耗时就是rdb文件通过网络进行传输。

从slave节点分析:slave节点在进行全量复制的时候还得先清空所有缓存数据,如果缓存数据量比较大也是需要一定时间的,另外就是加载rdb也非常耗时。还有就是如果开启了AOF重写的话,意味着slave还要进行耗时的AOF重写操作。

在介绍部分复制前,我这里特别说明一下,免得有些新的学者和我在学习这块内容的时候有同样的认知误区。

说明:

我们知道主从结构的数据同步,按照同步的时机可以分为slave刚启动与master连接时的初始化同步和正常运行过程中的数据修改同步,初始化的数据同步就是我们本篇文章介绍的全量复制,部分复制并非是在正常运行过程中的数据修改时的主从数据实时同步的方式,我刚开始学主从复制的时候一直错误的认为在正常的运行过程当中master如果有数据写更新的话是通过部分复制向slave节点实时同步数据的方式。关于在正常运行中master实时同步给slave数据的流程大家可以看下博客:。我们来具体看下部分复制在什么情况下会触发

部分复制使用 psync {runId} {offset} 命令实现,当redis主从结构正常运行时突然出现网络闪断或者抖动时导致命令丢失等异常情况时,master节点在这段不能正常实时给slave同步数据的期间会将更新的数据记录在复制积压缓冲区,当slave节点重新与master建立正常连接后,slave节点会向master节点要求补发丢失的命令数据,我们看下具体的流程图:

redis主从架构为什么至少3台机子 redis主从结构_Redis面试题 _14

  • 1. 出现主从节点连接丢失;
  • 2. 在主从中断期间master是能正常响应客户端的,但是更新的数据不能正常响应给slave节点,这个时候是将更新数据记录在复制积压缓存区中;
  • 3. 主从恢复连接;
  • 4. 恢复连接之后,因为不是初次与master建立主从关系,slave是保存着master的runid和复制偏移量offset,所以请求pysnc命令时会携带这两个参数。
  • 5. master节点收到psync后,首先核对runid是否和自己当前的runid是否一致,如果一致则,说明之前复制的是当前主节点;之后再根据参数offset在复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中,则响应slave节点CONTINUE,表示可以进行部分复制,有一点不满足将会进行全量复制;
  • 6. 主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,达到数据一致。

部分复制目的就是当出现网络中断等异常导致主从节点不能正常同步实时数据的情况下,在补发丢失数据时尽可能减少全量复制操作从而提升效率和性能。

四、总结

       到这里我们主从复制的实现和底层流程已经介绍完啦。本篇文章学习了什么是主从结构、主从结构的作用,再到学习redis主从结构的实现:主从复制,实现方式有两种:slaveof命令和配置文件方式,最后就是介绍全量复制和部分复制的流程。我们已经知道主从结构就是为了避免在单机服务架构下出现不可用的情况,那我们部署的主从架构出现了机器故障又该怎么办呢?下一篇文章我们就来学习学习,感谢阅读!