Redis高可用概述

Web 服务器中,高可用 是指服务器可以 正常访问 的时间,衡量的标准是在 多长时间 内可以提供正常服务(99.9%99.99%99.999% 等等)。在 Redis 层面,高可用 的含义要宽泛一些,除了保证提供 正常服务(如 主从分离快速容灾技术 等),还需要考虑 数据容量扩展数据安全 等等。

Redis 中,实现 高可用 的技术主要包括 持久化复制哨兵集群,下面简单说明它们的作用,以及解决了什么样的问题:

  • 持久化:持久化是 最简单的 高可用方法。它的主要作用是 数据备份,即将数据存储在 硬盘,保证数据不会因进程退出而丢失。
  • 主从复制:主从复制是高可用 Redis 的基础,哨兵集群 都是在 主从复制基础 上实现高可用的。主从复制主要实现了数据的多机备份以及对于读操作的负载均衡和简单的故障恢复。缺陷是故障恢复无法自动化、写操作无法负载均衡、存储能力受到单机的限制。
  • 哨兵:在主从复制的基础上,哨兵实现了 自动化故障恢复。缺陷是 写操作 无法 负载均衡存储能力 受到 单机 的限制。
  • 集群:通过集群,Redis 解决了 写操作 无法 负载均衡 以及 存储能力 受到 单机限制 的问题,实现了较为 完善高可用方案

本篇博客先介绍主从复制方案。复制的话主要是解决复杂环境中高可用的问题,后面章节的哨兵和集群都是在复制的基础上实现高可用的。

主从复制是在一个交换节点设立一高精度的基准时钟,通过传输链路把此基准时钟信号送到网中各个从节点,各个从节点利用锁相环技术把本地时钟频率锁定在基准时钟频率上,从而实现网内各节点之间的时钟信号同步 。简单点来说就是通过网络传输链路将主数据库的数据发送到某一台服务器上。建立一个和主数据库完全一样的数据库环境,称之为从数据库。后续如果主数据库的数据发生变化会及时的通知到从服务器上(从数据库会与主数据库建立连接)。

使用

1 建立配置

复制实例划分为主节点(master)和从节点(slave)。每个从节点只能有一个主节点,而主节点可以同时具有多个从节点。复制的数据流是单向的,只能由主节点复制到从节点。另外的话开启主从复制完全是在从节点发起的,不需要我们在主节点做任何事情。配置复制的方式有以下三种:配置文件、启动命令、客户端命令,这三种方式是等效的。

1.1 配置文件

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

1.2 启动命令

redis-server启动命令后添加参数 --slaveof <masterip> <masterport>

1.3 客户端命令

在客户端执行命令slaveof <masterip> <masterport>

2 准备实例

由于没有那么多服务器资源,这里的话就用一台服务器弄两个实例用于演示。其中,主数据库使用6379, 从数据库使用6380

redis双活主从节点分配_redis

3 建立复制

可以使用上面说的三种方式的任意一种,我这里的话使用上面1.3的通过客户端命令来建立连接。

## 进入从服务器
redis-cli -p 6380
## 获取 key为hello
127.0.0.1:6380> get hello
(nil)
## 获取主数据库数据
127.0.0.1:6379> get hello
"world"
## 在从数据库建立复制
127.0.0.1:6380> slaveof 127.0.0.1 6379
OK
## 在从数据库再次查询hello,已经能获取到
127.0.0.1:6380> get hello
"world"
## 在主数据库删除key(从数据库不能做写入操作,报错如下:(error) READONLY You can't write against a read only slave.)
127.0.0.1:6379> del hello
(integer) 1
## 在从数据库再次查询hello,已经被删除了
127.0.0.1:6380> get hello
(nil)
复制代码

4 断开复制

断开复制可以通过slaveof no one断开。需要注意的是,从节点断开复制后,不会删除已有的数据,只是不再接受主节点新的数据变化。主要流程第一断开与主节点复制关系,第二从节点晋升为主节点。

127.0.0.1:6380> slaveof no one
OK
复制代码

原理

redis双活主从节点分配_redis双活主从节点分配_02

主从复制流程图如上,共分成了六个步骤,下面针对每隔步骤单独聊一聊。

1. 保存配置

从节点服务器维护了masterhostmasterport两个字段,用于存储主节点的ipport(这个很好理解,应为要建立连接必须要这个字段)。有一点需要注意的是,slaveof是异步命令,从节点完成对主节点ipport保存后,会向发送slaveof命令的客户端直接返回OK,实际的复制操作还没有开始。

2. 建立连接

建立连接的过程是通过轮询主节点配置来建立的。从节点(slave)内部通过每秒运行的定时任务维护制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接。如果建立成功,则会为该socket建立一个专门处理复制工作的文件事件处理器,负责后续的复制工作,如接收RDB文件、接收命令传播等。如果从节点无法建立连接,定时任务会无限重试直到连接成功或者执行slaveof no one取消复制。

3. 发送 ping 命令

连接建立成功后从节点会发送ping请求进行首次通信,ping请求主要目的是检测当前socket是否可用和检测主节点当前是否可接受处理命令。如果发送ping命令后,从节点没有收到主节点的pong回复或者超时,比如网络超时或者主节点正在阻塞无法响应命令,从节点会断开复制连接,下次定时任务会发起重连。

4. 权限校验

如果从节点中设置了masterauth选项,则从节点需要向主节点进行身份验证。没有设置该选项,则不需要验证。从节点进行身份验证是通过向主节点发送auth命令进行的,auth命令的参数即为配置文件中的masterauth的值。 如果主节点设置密码的状态,与从节点masterauth的状态一致(一致是指都存在,且密码相同,或者都不存在),则身份验证通过,复制过程继续。如果不一致,则从节点断开 socket 连接,等待下次轮询重连。

5. 数据同步

当主从服务器正常通讯后,便可以开始进行数据同步。对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。Redis2.8版本以后采用新复制命令psync进行数据同步,原来的sync命令依然支持,保证新旧版本的兼容性。那新版本的同步的话有区分为全量同步和部分同步。

5.1 全量同步

一般用于初次复制场景,Redis 早期支持的复制功能只有全量复制,它会把主节点全部数据一次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销。

redis双活主从节点分配_主从_03

  1. 从节点内部会发出一个同步命令,由于是第一次进行复制,从节点没有复制偏移量和主节点的运行ID,所以发送psync-1
  2. 主节点根据psync-1解析出当前为全量复制,回复+FULLRESYNC和自己的runIdoffset
  3. 从节点接收主节点的响应数据保存运行ID、偏移量offset和主机master的基本信息。
  4. 主节点收到全量复制的命令后,执行bgsave(异步执行),在后台生成RDB文件(快照),并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令(类似于前面 AOF 重写时的两个缓冲区)。
  5. 主节点发送RDB文件到从节点。
  6. 对于从节点开始接收RDB快照到接收完成期间,主节点仍然响应读写命令,因此主节点会把这期间写命令数据保存在复制客户端缓冲区内,当从节点加载完RDB文件后,主节点再把缓冲区内的数据发送给从节点,保证主从之间数据一致性。
  7. 从节点接收完主节点传送来的全部数据后会清空自身旧数据。
  8. 从节点清空数据后开始加载RDB文件,对于较大的RDB文件,这一步操作依然比较耗时。
  9. 从节点成功加载完RDB后,如果当前节点开启了AOF持久化功能,它会立刻做bgrewriteaof操作,保证全量复制后AOF持久化文件立刻可用。

5.2 部分同步

细心的你会发现全量复制的 I/O开销是非常巨大的,那部分复制主要是 Redis 针对全量复制的过高开销做出的一种优化措施,使用psync{runId}{offset}命令实现。当从节点(slave)正在复制主节点(master)时,如果出现网络闪断或者命令丢失等异常情况时,从节点会向主节点要求补发丢失的命令数据,如果主节点的复制积压缓冲区内存在这部分数据则直接发送给从节点,这样就可以保持主从节点复制的一致性。补发的这部分数据一般远远小于全量数据,所以开销很小。

redis双活主从节点分配_redis双活主从节点分配_04

  1. 当主从节点之间出现网络抖动,如果超过repl-timeout时间,主节点会认为从节点故障并中断复制连接(connection lost)。
  2. 主从连接中断期间主节点依然响应命令,但因复制连接中断命令无法发送给从节点,不过主节点内部存在的复制积压缓冲区,依然可以保存最近一段时间的写命令数据,默认最大缓存1MB
  3. 从节点重试连接主节点,网络恢复后从节点会再次连上主节点。
  4. 从节点会把自己当前 runId和偏移量传输给主节点,并且执行 pysnc 命令同步。
  5. 节点接到 psync 命令后首先核对参数runId是否与自身一致,如果一致,说明之前复制的是当前主节点。然后根据参数offset在自身复制积压缓冲区查找,如果偏移量之后的数据存在缓冲区中,则对从节点发送+CONTINUE响应,表示可以进行部分复制。
  6. 主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态。

6. 持续监听

命令持续复制。当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性。

注意点

  1. 主从复制除了解决复杂环境下的高可用问题,还有一个功能就是用来做读写分离。这个上面有提到过。
  2. 如果使用了主从复制架构,那就必须要考虑一个问题。那就是主从数据不一致的问题。还有就是主从服务器直接配置不一致的问题。
  3. 在对 Redis 做主从复制时,尽量要避免全量数据复制。前面也有提到过全量复制是一个非常消耗资源的操作。

总结

关于一些注意点的话其实像读写分离这一块其实还是很有必要去了解的,后面看看有没有必要抽时间出来弄一篇。整个高可用配置的第一篇就差不多了,整个流程上的或者原理上的应该都讲清楚了,配合那就张图仔细想想整个流程应该是不难的。