深入学习Redis高可用的基石:主从复制

作者:微信小助手

发布时间:2018-09-18T00:26:51

在前面的两篇文章中,分别介绍了 Redis 的内存模型Redis 的持久化,今天我们来深入学习 Redis 的主从复制。


在 Redis 的持久化中曾提到,Redis 高可用的方案包括持久化、主从复制(及读写分离)、哨兵和集群。


其中持久化侧重解决的是 Redis 数据的单机备份问题(从内存到硬盘的备份);而主从复制则侧重解决数据的多机热备。此外,主从复制还可以实现负载均衡和故障恢复。


我将从以下几个部分详细介绍 Redis 主从复制的方方面面:

  • 主从复制概述

  • 如何使用主从复制

  • 主从复制的实现原理

  • 应用中的问题

  • 总结


主从复制概述


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


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


主从复制的作用主要包括:

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

  • 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写 Redis 数据时应用连接主节点,读 Redis 数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高 Redis 服务器的并发量。

  • 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是 Redis 高可用的基础。


如何使用主从复制


为了更直观的理解主从复制,在介绍其内部原理之前,先说明我们需要如何操作才能开启主从复制。


建立复制


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


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

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

  • redis-server 启动命令后加入 --slaveof <masterip> <masterport>。

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


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


实例


准备工作:启动两个节点。为了方便起见,实验所使用的主从节点是在一台机器上的不同 Redis 实例。


其中主节点监听 6379 端口,从节点监听 6380 端口;从节点监听的端口号可以在配置文件中修改:

启动后可以看到:

两个 Redis 节点启动后(分别称为6379节点和6380节点),默认都是主节点。


建立复制:此时在 6380 节点执行 slaveof 命令,使之变为从节点。

观察效果:下面验证一下,在主从复制建立后,主节点的数据会复制到从节点中。


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

然后在主节点中增加这个 key:

此时在从节点中再次查询这个 key,会发现主节点的操作已经同步至从节点:

然后在主节点删除这个 key:

此时在从节点中再次查询这个 key,会发现主节点的操作已经同步至从节点:

断开复制


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


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


从节点执行 slaveof no one 后,打印日志如下图所示;可以看出断开复制后,从节点又变回为主节点。

主节点打印日志如下:

主从复制的实现原理


上面一节中,我们介绍了如何操作可以建立主从关系;本小节将介绍主从复制的实现原理。


主从复制过程大体可以分为 3 个阶段:

  • 连接建立阶段(即准备阶段)

  • 数据同步阶段

  • 命令传播阶段


连接建立阶段


该阶段的主要作用是在主从节点之间建立连接,为数据同步做好准备。


步骤 1:保存主节点信息


从节点服务器内部维护了两个字段,即 masterhost 和 masterport 字段,用于存储主节点的 ip 和 port 信息。


需要注意的是,slaveof 是异步命令,从节点完成主节点 ip 和 port 的保存后,向发送 slaveof 命令的客户端直接返回 OK,实际的复制操作在这之后才开始进行。


这个过程中,可以看到从节点打印日志如下:


步骤 2:建立 Socket 连接


从节点每秒 1 次调用复制定时函数 replicationCron(),如果发现了有主节点可以连接,便会根据主节点的 ip 和 port,创建 socket 连接。


如果连接成功,则:

  • 从节点:为该 socket 建立一个专门处理复制工作的文件事件处理器,负责后续的复制工作,如接收 RDB 文件、接收命令传播等。

  • 主节点:接收到从节点的 socket 连接后(即 accept 之后),为该 socket 创建相应的客户端状态,并将从节点看做是连接到主节点