redis 主从复制

Redis中,用户可以使用slaveof命令或者slaveof配置项,让一个服务器去复制另一个服务器。进行复制中的主从服务器双方的数据库将保存相同的数据(一致性)。
1)通过命令:
127.0.0.1:6380> slaveof 127.0.0.2 6379
上面的命令表示:端口为6380的服务器 开始复制 端口为6379的服务器。

2)通过配置文件:
主服务器不用做任何修改,在从服务器的配置文件中作如下修改:
slaveof 192.168.0.100 6379 (映射到主服务器上)
如果master设置了验证密码,还需配置masterauth。楼主的master设置了验证密码为admin,所以配置masterauth admin。配置完之后启动slave的Redis服务,OK,主从配置完成。

在master和slave分别执行info命令,查看结果如下,
主服务器:

1
2
3
4
5
6
7
8
9
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.2,port=6380,state=online,offset=10394,lag=0
master_repl_offset:10394
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:10393

从服务器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Replication
role:slave
master_host:127.0.0.2
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:10436
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

注:

当从服务器执行了slaveof命令后,从服务器中原来的数据将清空,重新加载主服务器中的数据。

Redis2.8版本之前使用了旧版复制功能,2.8之后开始使用新版本的功能。

旧版复制:

1、旧版复制实现:
1)复制功能分为同步和命令传播两个步骤:

  • 同步:将从服务器的数据库状态更新成主服务器当前的数据库状态;
  • 命令传播:当主服务器的数据库状态被修改,导致主从服务器状态不一致,让主从服务器数据库状态重新回到一致状态;

2)同步:
当客户端向从服务器发送slaveof命令后,要求从服务器复制主服务器时,从服务器首先要执行同步操作,具体为从服务器向主服务器发送SYNC命令,步骤如下:

  • 从服务器向主服务器发送SYNC命令;
  • 收到SYNC命令的主服务器开始执行bgsave,在后台生成一个rdb文件;并用一个缓冲区记录从现在开始执行的所有写命令;
  • 主服务器bgsave执行完毕后,将rdb文件发送给从服务器;从服务器收到后载入该rdb文件,将从数据库状态更新成主服务器执行bgsave时的状态;
  • 主服务器将记录在缓冲区中的写命令发送给从服务器;从服务器执行这些命令,将其状态更新成主服务器当前的妆台;

3)命令传播:
在同步操作完毕后,主从服务器达到了一致的状态,但这种状态不是一成不变的。当主服务器执行了写操作后,主服务器会对从服务器执行命令传播操作,将相应的写命令发送给从服务器,从服务器执行该命令,从而达到一致性。

4)缺陷:
旧版复制过程中,如果主从服器出现断线,当从服务器重新连接上后,这时,由于主从服务器状态不一致,所以从服务器向主服务器发送SYNC命令。这时,主服务器会按照上面的步骤执行bgsave….操作。

  • SYNC是一个比较耗资源的操作;
  • 断线期间,可能只有部分数据发生了修改;为了使这一部分数据达到一致性而执行SYNC,这种方式比较低效。

新版复制:

为了解决旧版复制的缺陷,2.8 以后使用PSYNC命令代替原来的SYNC命令。PSYNC具有 完全同步和 部分同步两种模式。

  • 完全同步:用于处理初次复制情况,和SYNC执行步骤基本相同,发送RDB文件、执行缓冲区写命令;
  • 部分同步:用于处理断线后的重复制操作;从服务器重新连线后,如果条件允许,主服务器会将断线期间的写命令发送给从服务器,否则执行完全同步;

1、部分同步功能由三部分构成:

  • 主服务器的复制偏移量、和从服务器的复制偏移量;
  • 主服务器的复制积压缓冲区;
  • 服务器的运行ID;

1)偏移量:
主从服务器双方都会维护一个复制偏移量:

  • 主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量之加上N;
  • 从服务器收到主服务器传播来的N个字节数据时,就将自己的复制偏移量之加上N;
    通过对比主从服务器的复制偏移量是否相同,就可以知道主从服务器是否处于一致性状态;

2)复制积压缓冲区:

复制积压缓冲区 是由主服务器维护的一个固定长度、先进先出(FIFO)队列,默认大小为1M。当进行命令传播时,主服务器不仅会将写命令发送给所有从服务器,同时将写命令放入积压缓冲区(队列)中。

在积压缓冲区中,会为队列的每个字节记录相应的复制偏移量

在从服务器断线重新连接上后,从服务器通过PSYBC命令将自己的偏移量发给主服务器,主服务器根据这两个量来判断执行何种同步操作:

- 如果偏移量后的数据存在复制积压缓冲区中,那么主服务器对从服务器执行部分操作;
- 如果偏移量后的数据不存在复制积压缓冲区中,那么主服务器对从服务器执行完整同步操作;

注:
> 根据需要调整复制积压缓冲区大小,一般可根据公式 :2 断线时间 主服务器每秒写命令数量;

3)运行ID:
无论主从服务器,redis都会有自己的运行ID。(由40个随机的十六位字符组成) 当从服务器对主服务器进行初次复制时,主服务器会将自己的ID发给从服务器,从服务器会将这个ID保存起来。当从服务器重新连上一个主服务器时,会向当前主服务器发送之前保存的ID:

- 如果从服务器保存的ID和当前主服务器ID一样,说明从服务器断线之前复制的就是这个主服务器,主服务器可以尝试使用部分同步;
- 如果从服务器保存的ID和当前主服务器ID不一样,说明从服务器断线前复制的不是这个主服务器,这时主服务器对从服务器执行完整同步操作。

2、PSYNC实现:
1)PSYNC命令有以下两种调用方式:

- 如果从服务器以前没有复制过任何主服务器,或者执行过 slaveof no one 命令,那么从服务器开始向主服务器发送PSYNC ? -1 命令,主动请求主服务器进行完整同步;
- 如果从服务器复制过某个主服务器,那么从服务器开始向主服务器发送PSYNC ,其中runid是上次保存的主服务器运行ID,offset是自己的偏移量。

2)主服务器收到PSYNC命令后,根据实际情况会返回如下:

- +FULLRESYNC ,表示主服务器对从服务器执行完整同步;其中runid为主服务器运行ID,从服务器收到后会保存起来;offset为主服务器的当前复制偏移量,从服务器根据他初始化自己的偏移量;
- 返回+CONTINUE回复,表示主服务器对从服务器执行部分同步,这时从服务器等待主服务器发送的命令即可;
- 返回-ERR恢复,表示主服务器不识别PSYNC,从服务器将发送SYNC命令;


3、心跳检测:
1)在命令传播阶段,从服务器默认每秒1次的频率向主服务器发送命令:REPLCONF ACK
其中,replication_offset是从服务器的复制偏移量,发送该命令目的:

- 检测主从服务器的网络连接状况;
- 辅助实现min-slaves选项;
- 检测命令丢失;

2)检测网络状况:
如果主服务器1秒内没有收到从服务器发送的REPLCONF ACK 命令,那么主服务器认为主从之间连接出现问题了。通过在主服务器上执行info replication 在slave的lag一栏,可以看到从服务器最后一次向主服务器发送REPLCONF ACK 命令距离现在过了多少秒。正常情况下,lag在0和1之间跳动。
1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.2,port=6380,state=online,offset=9652,lag=0
master_repl_offset:9652
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:9651

3)实现min-slaves:

redis的min-slaves-to-write和min-slaves-max-lag两个选项,可以防止主服务器在不安全的情况系执行写命令。

例如,主服务器设置:
min-slaves-to-write 3
min-slaves-max-lag 10
那么,从服务器数量少于3,或者3个从服务器的延时(lag)值都大于等于10秒时,主服务器将拒绝执行写命令。可以通过在主服务器上执行 info replication 命令查看lag值。

4)检测命令丢失:

如果因为网络,主服务器发送给从服务器的写命令半路丢失,那么当从服务器发送REPLCONF ACK命令时,主服务器将发现从服务器的偏移量少于自己的复制偏移量,然后主服务器会根据从服务器的复制偏移量从复制积压缓冲区中取出对应的写命令,重新发给从服务器。