深悉Redis的主从模式原理

前言

redis在高并发场景下,可以称作是一个利器,一方面可以作为缓存技术,另一方面可以作为分布锁的实现方案。

对于单节点的redis来说,它会有自己的瓶颈,所以往往会采用redis集群来负载高并发。其中应用比较多的就是主从模式,也就是采用读写分离模式。

深悉Redis的主从模式原理_第1张图片

下面来首先来探讨下,redis的主从模式的搭建,以及主从同步的原理。

搭建过程

首先采用的是一主两从的方式,(本机IP:192.168.0.2),如图:

深悉Redis的主从模式原理_第2张图片
  • master:192.168.0.2:7001

  • slave-1:192.168.0.2:7002

  • slave-2:192.168.0.2:7003

docker执行的命令如下:

# master 节点命令dockerrun-d-p7001:6379--networkredis--nameredis-master--privileged=true-v/Volumes/bto/redis/master-slave/7001:/dataredis:6.2.4# slave-1 节点命令dockerrun-d-p7002:6379--networkredis--nameredis-node-1--privileged=true-v/Volumes/bto/redis/master-slave/7002:/dataredis:6.2.4# slave-2 节点命令dockerrun-d-p7003:6379--networkredis--nameredis-node-2--privileged=true-v/Volumes/bto/redis/master-slave/7003:/dataredis:6.2.4

备注:docker的命令这里不做过多的赘述,上网一搜一大堆说明。

执行完上述命令后,执行docker ps查看运行结果,如下图:

上图可以看出,已经运行起来三个redis实例,但是此时的三个实例之间还不是主从关系,接下来建立主从,以redis-slave-1为例:

可以通过docker命令进入容器内,或者在宿主机上直接操作,这里我选择的是在宿主机上直接操作,首先链接7002实例,命令如下:

redis-cli -h 192.168.0.2 -p 7002

进入后,执行命令:

slaveof 192.168.0.2 7001 

来指明它的主节点是7001。(7003同理)

【注意】从redis 5.0版本开始,该命令已经过时,应该用replicaof命令来代替slaveof。我本地用的是6.4.2,主要是习惯了slaveof。官网说明如下图:

深悉Redis的主从模式原理_第3张图片

此时连接上7001,执行如下命令,查看从节点信息:

info replication
深悉Redis的主从模式原理_第4张图片

可以看出slaves是2个节点。其中的ip=172.21.0.1是docker容器中的ip。

然后来验证下:

  • 在master-7001上进行新增,然后看下7002,7003从节点的数据。执行结果如下图:

深悉Redis的主从模式原理_第5张图片

在7001的主节点上,新增加了{key:value} = {username:zhangsan}的数据。然后在7002和7003上分别获取,得到了相同的结果。

  • 尝试在从节点 7002、7003节点上进行增加操作,执行结果如图所示:

深悉Redis的主从模式原理_第6张图片

此时,redis会返回一个error结果:

READONLY You can't write against a read only replica.

就从节点是只读,无法写入。

其实上述搭建的过程很简单,没有太大的难度。接下来分析下主从数据同步的原理。

对于主从数据同步的原理呢,分为全量同步和增量同步。这篇博客主要探讨全量同步。

全量同步

在描述全量同步的过程之前,先来认识两个概念:

  1. replid:是实例节点的唯一表示。

  1. offset:数据的偏移量。

也就是说每个redis实例在启动的时候,都会有一个replid唯一表示,实际上完整叫master_replid,因为首次启动的redis时候它都是一个主节点(前提:没有在配置文件中进行配置主从),而offset可以理解成分页数据。比如:启动7001、7002后的信息如下:

深悉Redis的主从模式原理_第7张图片

上图左侧为redis:7001,右侧为redis:7002。在没有进行主从配置的时候,它们都是主节点,也就是role:master(上图红色框),同时都有各自的replid(绿色狂),其中:

  • 7001-replid: c1e5b2e6c931b5b40bb80ec79ad07babfce7e44d

  • 7002-replid:50452115cb9093ac6562357dfb59eb5059c33aa5

而各自的offset为:

  • 7001-offset: 0

  • 7002-offset:0

下面探讨下,主从数据同步的原理,如图:

深悉Redis的主从模式原理_第8张图片

上图是redis进行数据全量同步的过程,这里分成了三个阶段:

  • 【第一阶段】:当redis实例节点7002,执行slaveof(或replicaof) 192.168.0.2 7001 命令的时候,会向master发送自己的replid和offset给7001,然后尝试进行增量同步。当7001接收到后发现replid与自己的不一样,说明是第一次建立主从关系,所以就会拒绝【增量同步】,而是选择【全量同步】,并把自己(7001)的replid和offset发送给7002,7002再接收这些信息后会保存起来。

  • 【第二阶段】:在7001向7002发送replid、offset信息的同时,会有一个【独立进程】生成rdb文件,然后把生成好的rdb文件发送给7002。7002再接收到数据后,会把本地的数据进行清空(包括内存与rdb文件),然后读取7001发送过来的rdb文件,并把数据加载到内存中。但是在7001(master)生成rdb的时候是很耗时的,同时因为主节点是可以被写入的,因此在生成rdb的时候,如果有client端对master节点(7001)进行了操作,后台进程会把这些操作命令写入到一个日志中---repl_backlog。

  • 【第三阶段】由于在第二步生成了repl_backlog,所以master节点会采用一定策略把repl_backlog发送给从节点,从节点再接收到日志文件后,再进一步同步本地的数据。

该三阶段就是redis主从全量同步的流程。具体这个流程是怎么来的呢?这是通过日志分析出来的,接下来看下具体的日志信息。

日志分析

为了方便查看日志的流程,我在宿主机上进行手动进行启动7001、7002两个redis实例,并通过redis-cli连接7002,如下图:

深悉Redis的主从模式原理_第9张图片

然后我在7001中随便添加了几个数据(这里不再演示),主要是为了展示offset。

建立主从,在7002中执行命令:

replicaof 127.0.0.1 7001
深悉Redis的主从模式原理_第10张图片

输出的日志:

深悉Redis的主从模式原理_第11张图片

上屏是7001的日志,下屏是7002的日志。

首先,7002开始尝试能发ping通7001,来确定是否可以建立连接 ,如下图:

深悉Redis的主从模式原理_第12张图片

然后通过后,7002开始尝试向7001请求数据,并把自己的repid、offset发给7001,如下图:

深悉Redis的主从模式原理_第13张图片

采用的是

  • partial resynchronization:增量同步

  • repid: 095911a80dc2a318ea60b16b2a0260228896ee7f(7002的repid)

  • offset: 1

然后7001接收到7002发送来的信息,如下图:

深悉Redis的主从模式原理_第14张图片

7001会产生如下信息:

  • partial resynchronization not accepted:不允许增量同步。

  • 7002你发过来的replid为095911a80dc2a318ea60b16b2a0260228896ee7f,我的replid是0a0856578570a2d61c694a37aeda7436d288d25d是这个,咱俩不一样,所以给你全量同步。

  • 然后开始bgsave生成rdb文件,如下图:

深悉Redis的主从模式原理_第15张图片

后台进程为26853,生成完rdb文件后,发送给7002。

7002此时接收到来自7001的rdb文件,如下图:

深悉Redis的主从模式原理_第16张图片

开始全量同步,其中包括了【Flushing old data】清空旧的数据,【 Loading DB in memory】把rdb中的数据加载到内存中。这样就完成了主从同步,其实背后还有一个repl_backlog的过程,只是没有在日志中显示。

你可能感兴趣的:(redis,redis)