05-Redis 多机之1 - 主从复制

1 主从复制

主从复制 是指将一台 Redis 服务器的数据,复制到其他的 Redis 服务器。前者称为 **主节点(master)**,后者称为 **从节点(slave)**。

数据的复制是 单向 的,只能由主节点到从节点。

默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

Redis 主从复制支持 主从同步从从同步 两种,后者是 Redis 后续版本新增的功能,以减轻主节点的同步负担。

2 主从复制的作用

  • 数据冗余: 主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 故障恢复: 当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复(实际上是一种服务的冗余)。
  • 负载均衡: 在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写 Redis 数据时应用连接主节点,读 Redis 数据时应用连接从节点),分担服务器负载。尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高 Redis 服务器的并发量。
  • 高可用基石: 除了上述作用以外,主从复制还是哨兵和集群能够实施的 基础,因此说主从复制是 Redis 高可用的基础。

3 快速体验

Redis 中,用户可以通过执行 SLAVEOF 命令或者设置 slaveof 选项,让一个服务器去复制另一个服务器,以下三种方式是 完全等效 的:

  • 配置文件:在从服务器的配置文件中加入:slaveof <masterip> <masterport>
  • 启动命令:redis-server 启动命令后加入 --slaveof <masterip> <masterport>
  • 客户端命令:Redis 服务器启动后,直接通过客户端执行命令:slaveof <masterip> <masterport>,让该 Redis 实例成为从节点。

注意:主从复制的开启,完全是在从节点发起的,不需要我们在主节点做任何事情。

实验所使用的主从节点是在一台机器上的不同Redis实例,其中主节点监听6379端口,从节点监听6380端口

3.1 第一步:本地启动两个节点

安装好 Redis 之后,我们可以使用 redis-server --port <port> 的方式指定创建两个不同端口的 Redis 实例,例如分别创建端口为 63796380 两个 Redis 实例:

1
2
3
4
5
# 创建一个端口为 6379 的 Redis 实例
redis-server --port 6379

# 创建一个端口为 6380 的 Redis 实例
redis-server --port 6380

此时两个 Redis 节点启动后,都默认为 主节点

3.2 第二步:建立复制

我们在 6380 端口的节点中执行 slaveof 命令,使之变为从节点:

1
2
3
# 在 6380 端口的 Redis 实例中使用控制台
redis-cli -p 6380
127.0.0.1:6380> SLAVEOF 127.0.0.1ø 6379OK # 成为本地 6379 端口实例的从节点

3.3 第三步:观察效果

下面我们来验证一下,主节点的数据是否会复制到从节点之中:

  • 先在 从节点 中查询一个 不存在 的 key:

    1
    2
    127.0.0.1:6380> GET mykey
    (nil)
  • 再在 主节点 中添加这个 key:

    1
    127.0.0.1:6379> SET mykey myvalueOK
  • 此时再从 从节点 中查询,会发现已经从 主节点 同步到 从节点

    1
    2
    127.0.0.1:6380> GET mykey
    "myvalue"

3.4 第四步:断开复制

通过 slaveof <masterip> <masterport> 命令建立主从复制关系以后,可以通过 slaveof no one 断开。

需要注意的是,从节点断开复制后,不会删除已有的数据,只是不再接受主节点新的数据变化。

从节点执行 slaveof no one 之后,从节点和主节点分别打印日志如下:

1
2
3
4
5
6
7
8
# 从节点打印日志
61496:M 17 Mar 2020 08:10:22.749 # Connection with master lost.
61496:M 17 Mar 2020 08:10:22.749 * Caching the disconnected master state.
61496:M 17 Mar 2020 08:10:22.749 * Discarding previously cached master state.
61496:M 17 Mar 2020 08:10:22.749 * MASTER MODE enabled (user request from 'id=4 addr=127.0.0.1:55096 fd=8 name= age=1664 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=34 qbuf-free=32734 obl=0 oll=0 omem=0 events=r cmd=slaveof')

# 主节点打印日志
61467:M 17 Mar 2020 08:10:22.749 # Connection with replica 127.0.0.1:6380 lost.

4 实现原理简析

上图为 Redis 主从复制的原理, 可以分为成三个阶段:准备阶段-数据同步阶段-命令传播阶段

更详细的步骤请参考:https://www.cnblogs.com/kismetv/p/9236731.html

除此之外,我们还要进行一些其他说明。

4.1 身份验证 | 主从复制安全问题

如果 主节点 配置 requirepass 设置了密码,那 从节点 该怎么设置呢?

我们可以在 从节点 中对应配置 masterauth 参数 (与主节点 _requirepass_ 保持一致), 这样就能够进行正常复制了。

4.2 SYNC 命令是一个非常耗费资源的操作

每次执行 SYNC 命令,主从服务器需要执行如下动作:

  1. 主服务器 需要执行 BGSAVE 命令来生成 RDB 文件,这个生成操作会 消耗 主服务器大量的 CPU、内存和磁盘 I/O 的资源
  2. 主服务器 需要将自己生成的 RDB 文件 发送给从服务器,这个发送操作会 消耗 主服务器 大量的网络资源 (带宽和流量),并对主服务器响应命令请求的时间产生影响;
  3. 接收到 RDB 文件的 从服务器 需要载入主服务器发来的 RBD 文件,并且在载入期间,从服务器 会因为阻塞而没办法处理命令请求

特别是当出现 断线重复制 的情况是时,为了让从服务器补足断线时确实的那一小部分数据,却要执行一次如此耗资源的 SYNC 命令,显然是不合理的。

PSYNC 命令的引入

所以在 Redis 2.8 中引入了 PSYNC 命令来代替 SYNC,它具有两种模式:

  1. 全量复制: 用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作;

  2. 部分复制: 用于网络中断等情况后的复制,只将 中断期间主节点执行的写命令 发送给从节点,与全量复制相比更加高效。
    需要注意 的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制;

    部分复制的原理主要是靠主从节点分别维护一个 复制偏移量,有了这个偏移量之后断线重连之后一比较,之后就可以仅仅把从服务器断线之后确实的这部分数据给补回来了。

更多的详细内容可以参考:https://www.cnblogs.com/kismetv/p/9236731.html

参考资料

  1. https://www.cnblogs.com/wmyskxz/p/12511834.html
  2. 《Redis 设计与实现》 | 黄健宏 著 - http://redisbook.com/
  3. 深入学习Redis(3):主从复制 - https://www.cnblogs.com/kismetv/p/9236731.html

05-Redis 多机之1 - 主从复制
https://flepeng.github.io/041-Redis-41-核心概念-05-Redis-多机之1-主从复制/
作者
Lepeng
发布于
2021年1月1日
许可协议