Redis 高可用(一) 主从理论
Redis 高可用主要是使用 主从复制 和 哨兵来做,集群不能算是高可用,因为当节点B有大量的数据,如果节点B挂掉,就再无法访问到节点B的数据,因为其他节点并不会有节点B的数据。其中的原因跟本身Redis的设计有关。
复制
使用和配置主从复制非常简单,从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。
这个系统的运行依靠三个主要的机制:
- 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave ,包括客户端的写入、key 的过期或被逐出等等(增量)。
- 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令。
- 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令到 slave 。
Redis 默认使用异步复制,其特点是低延迟和高性能。slave 服务会异步地确认其从 master 服务器周期接收到的数据量。
Redis 复制的非常重要的事实:
- Redis 使用异步复制,slave 和 master 之间异步确认处理数据。
- 一个 master 可以拥有多个 slave
- slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外, slave 之间也可以像层叠状的结构连接到其他 slave 。自 Redis 4.0 起,所有的 sub-slave 将会从 master 收到完全一样的复制流。
![](https://img.haomeiwen.com/i13859779/3f3e4f74276c4fd5.png)
- Redis 复制在 master 是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时,可以继续处理查询请求。
- 主从复制对于 slave 服务器来说也是非阻塞的,这意味着,即使从redis在进行主从复制过程中也可以接受外界的查询请求,只不过这时候 slave 返回的是以前老的数据,如果你不想这样,那么在启动redis时,可以在配置文件中进行设置,那么 slave 在复制同步过程中来自外界的查询请求都会返回错误给客户端;(虽然说主从复制过程中对于 slave 是非阻塞的,但是当 slave 从 master 同步过来最新的数据后还需要将新数据加载到内存中,在加载到内存的过程中是阻塞的,在这段时间内的请求将会被阻,但是即使对于大数据集,加载到内存的时间也是比较多的)
- 主从复制提高了redis服务的扩展性,避免单个redis服务器的读写访问压力过大的问题,同时也可以给为数据备份及冗余提供一种解决方案;
- 为了避免 master 服务器写磁盘压力带来的开销,可以配置让 master 不在将数据持久化到磁盘,而是通过连接让一个配置的 slave 服务器及时的将相关数据持久化到磁盘,不过这样会存在一个问题,就是 master 服务器一旦重启,因为 master 服务器数据为空,这时候通过主从同步可能导致从 slave 服务器上的数据也被清空;
强烈建议在 master 和在 slave 中启用持久化。否则会有如下问题:
我们设置节点 A 为 master 并关闭它的持久化设置,slave B 和 C 从 节点 A 复制数据。节点 A 崩溃,但是他有一些自动重启的系统可以重启进程。但是由于持久化被关闭了,节点重启后其数据集合为空。节点 B 和 节点 C 会从节点 A 复制数据,但是节点 A 的数据集是空的,因此复制的结果是它们会销毁自身之前的数据副本。
当 Redis Sentinel 被用于高可用并且 master 关闭持久化,这时如果允许自动重启进程也是很危险的。例如, master 可以重启的足够快以致于 Sentinel 没有探测到故障,因此上述的故障模式也会发生。
工作模式
Redis不管是旧版还是新版,复制的实现都可以分为七个步骤:
![](https://img.haomeiwen.com/i13859779/03ccd0abf323582d.png)
1. 设置主服务的地址与端口
127.0.0.1:12345> SLAVEOF 127.0.0.1 6379
当客户端向 slave 器发送以上命令时或者在配置文件中配置slaveof选项。slave 将向发送 SLAVEOF 命令的 客户端 返回OK,表示复制指令已经被接收,而实际上复制工作是在OK返回之后进行。
2. 建立套接字连接
![](https://img.haomeiwen.com/i13859779/c1454b474fbb4681.png)
slave 器根据设置的套接字创建连向 master 的套接字连接。 master 接收 slave 器的套接字连接之后,为该套接字创建响应的客户端状态,并将此时的 slave 器看做是 master 的客户端,也就是该 slave 器同时具备服务器与客户端两个身份。
3. 发送PING命令
![](https://img.haomeiwen.com/i13859779/748e1daa3ae8a149.png)
slave 成为 master 的客户端之后,做的第一件事就是向 master 发送PING命令。PING命令主要有两种作用:
- 虽然建立了套接字连接,但是还未使用过,通过发送PING命令检查套接字的读写状态是否正常
- 通过发送PING命令检查 master 能否正常处理命令请求
slave 在发送PING命令之后将遇到以下三种情况的其中一种:
- master 向 slave 返回一个回复,但是 slave 却不能在规定的会时间(timeout)内读取命令回复的内容,则表示当前主 slave 之间的网络状态连接不佳,不能基础执行复制工作的后续步骤,这时 slave 会断开套接字连接重新创建。
- master 向 slave 返回一个错误,那么表示 master 暂时没有办法处理 slave 器的命令请求,不能继续执行复制工作的后续步骤,这时 slave 会断开套接字连接重新创建。
- 如果 slave 读取到“PONG”回复,那么表示主从之间网络连接正常,并且 master 可以处理 slave 发送的命令请求。
4. 身份验证
slave 接收到 master 返回的“PONG”回复,接下来就需要考虑身份验证的事。
![](https://img.haomeiwen.com/i13859779/23a1f83cae4a0db9.png)
如果 slave 设置了 masterauth 选项,那么进行身份验证
如果 slave 没有设置 masterauth 选项,那么不进行身份验证
slave 在身份验证的时候可能遇到三种情况
- 主服务没有设置 requirepass 选项,并且 slave 也没有设置 masterquth 选项,那么 master 继续执行 slave 命令,完成复制工作
- 如果 slave 通过AUTH命令发送的密码与 master 中requirepass密码相同,那么 master 将继续执行 slave 发送的命令,复制工作继续,与此相反,密码不一致,则会返回 invalid password 错误
- 如果 slave 没有设置 masterauth 选项,而 master 设置了 requirepass 选项,那么 master 将返回一个NOAUTH错误。反之没有设设置 masterauth 选项,而设置了 requirepass 选项,那么会返回 no password is set 错误。
5. 发送端口信息
在身份验证步骤之后,slave 将执行命令REPLCONF listening-port <port>,向 master 发送 slave 的监听端口号。
6. 同步 7. 命令传播
slave 向 master 发送PSYNC命令,执行同步操作,值得注意的是只有 slave 是 master 的客户端,但是执行同步操作之后,master 也会成为 slave 的客户端。
master | slave | 备注 |
---|---|---|
主从完成同步 | 主从完成同步 | 主从都启动,并完成同步 |
set k1,v1 | set k1,v1 | master 执行set会传播到slave 进行set |
set k2,v2 | set k2,v2 | master 执行set会传播到slave 进行set |
...... | ...... | 更多的操作 |
主从断开连接 | 主从断开连接 | slave故障停止了同步操作 |
set k5002,v5002 | slave 尝试重新连接 | |
set k5003,v5003 | slave 尝试重新连接 | |
主从重连接成功 | 主从重连接成功 | 主从重连接成功 |
PSYNC | 连接成功,slave 向 master 发送PSYNC命令,执行同步,以上第6步 | |
向slave返回+CONTINUE,并执行同步 | ||
接收+CONTINUE | slave 接收+CONTINUE,准备执行部分同步 | |
向 slave 发送 set k5002,v5002 和 set k5003,v5003 命令 | ||
set k5002,v5002 set k5003,v5003 | 从接收到命令并执行 | |
主从完成同步 | 主从完成同步 | 同步完成 |
高版本的 Redis slave 默认为只读。