主从复制的实现原理

总的来说主从复制功能的详细步骤可以分为7个步骤:

  1. 设置主节点的地址和端口
  2. 建立套接字连接
  3. 发送PING命令
  4. 权限验证
  5. 同步
  6. 命令传播

接下来分别叙述每个步骤,整个流程图如下:
为了测试,我在本地机开启两个Redis节点,分别监听:
127.0.0.1 6379(主)
127.0.0.1 6380(从)

1. 设置主服务器的地址和端口

第一步首先是在从服务器设置需要同步的主服务器信息,包括机器IP, 端口。
主从复制的开启,完全是在从节点发起的;不需要我们在主节点做任何事情。

从节点开启主从复制,有3种方式:

(1)配置文件

在从服务器的配置文件中加入:slaveof masterip masterport

(2)启动命令

redis-server启动命令后加入 --slaveof masterip masterport

(3)客户端命令

Redis服务器启动后,直接通过客户端执行命令:slaveof masterip masterport,则该Redis实例成为从节点。

上述3种方式是等效的,下面以客户端命令的方式为例,看一下当执行了slaveof后,Redis主节点和从节点的变化。

完成上面的配置后, 从服务器会将主服务器的ip地址和端口号保存到服务器状态的属性里面。可以Redis使用info Replication 命令分别查看从服务器和主服务器的主从信息

2. 建立套接字连接

在slaveof命令执行之后,从服务器会根据设置的ip和端口,向主服务器简历socket连接。
在6380从服务器里面执行完slave of 127.0.0.1 6379后意味着,从服务器向主服务器发起socket连接
在执行info Replication 命令,可以看到6380服务器的角色是slave了

而6379 服务器已经成为主服务器角色:

3. 发送PING命令

从节点成为主节点的客户端之后,发送ping命令进行首次请求,目的是:检查socket连接是否可用,以及主节点当前是否能够处理请求。

从节点发送ping命令后,可能出现3种情况:

(1)返回pong:说明socket连接正常,且主节点当前可以处理请求,复制过程继续。

(2)超时:一定时间后从节点仍未收到主节点的回复,说明socket连接不可用,则从节点断开socket连接,并重连。

(3)返回pong以外的结果:如果主节点返回其他结果,如正在处理超时运行的脚本,说明主节点当前无法处理命令,则从节点断开socket连接,并重连。

主从发送PING命令流程图如下:

4. 身份验证

如果从节点中设置了masterauth选项,则从节点需要向主节点进行身份验证;没有设置该选项,则不需要验证。从节点进行身份验证是通过向主节点发送auth命令进行的,auth命令的参数即为配置文件中的masterauth的值。

如果主节点设置密码的状态,与从节点masterauth的状态一致(一致是指都存在,且密码相同,或者都不存在),则身份验证通过,复制过程继续;如果不一致,则从节点断开socket连接,并重连。

主从身份验证流程图如下:

5. 同步

同步就是将从节点的数据库状态更新成主节点当前的数据库状态。具体执行的方式是:从节点向主节点发送psync命令(Redis2.8以前是sync命令),开始同步。
数据同步阶段是主从复制最核心的阶段,根据主从节点当前状态的不同,可以分为全量复制部分复制下面会有详细介绍全量复制和部分复制内容,这里暂不详述

6. 命令传播

经过上面同步操作,此时主从的数据库状态其实已经一致了,但这种一致的状态的并不是一成不变的。
在完成同步之后,也许主服务器马上就接受到了新的写命令,执行完该命令后,主从的数据库状态又不一致。

数据同步阶段完成后,主从节点进入命令传播阶段;在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。

另外命令转播我们需要关注两个点: 延迟与不一致 和 心跳机制 我们下面介绍一下

延迟与不一致
需要注意的是,命令传播是异步的过程,即主节点发送写命令后并不会等待从节点的回复;因此实际上主从节点之间很难保持实时的一致性,延迟在所难免。数据不一致的程度,与主从节点之间的网络状况、主节点写命令的执行频率、以及主节点中的repl-disable-tcp-nodelay配置等有关。

repl-disable-tcp-nodelay 配置如下:

  • 假如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟(40ms),造成master与slave数据不一致
  • 假如设置成no,则redis master会立即发送同步数据,没有延迟

概括来说就是:前者关注性能,后者关注一致性

具体发送频率与Linux内核的配置有关,默认配置为40ms。当设置为no时,TCP会立马将主节点的数据发送给从节点,带宽增加但延迟变小。

一般来说,只有当应用对Redis数据不一致的容忍度较高,且主从节点之间网络状况不好时,才会设置为yes;多数情况使用默认值no