Redis - 主从架构
一、主从架构
单机 Redis ,能够承受的 QPS 大概在上万到几万不等,对于缓存来说,一般都是用来支撑读高并发的,因此架构做成主从架构,一主多从
- 主负责写,写的时候将数据复制同步到其他从节点
- 从负责读,所以的读请求走从节点
通过主从架构,可以轻松实现水平扩容,支撑读的高并发
主从架构步保证高可用:
-
Slave 挂了,不会影响可用性,还有其他的 Slave 提供相同数据,相同的对外读服务
-
Master 挂了,没法写数据了,就真的废了,系统相当于不可用
Redis 使用主备切换机制,来实现高可用架构,而内置的主备切换机制也就是哨兵模式
实现的
二、主从复制
2.1 复制
Redis 主从复制的大体流程如下:
- 采用异步复制数据到 Slave Node,Redis 2.8 开始,Slave Node 会周期性地确认自己每次复制的数量
- 一个 Master Node 可以配置多个 Slave Node
- Slave Node 可以连接其他的 Slave Node
- Slave Node 做复制的时候,不会阻塞 Master Node 的正常工作
- Slave Node 在复制的时候,也不会阻塞对自己的查询操作,此时它使用旧的数据集来提供服务,但是复制完成,就会删除旧数据集,加载新数据集,此时就会停止对外服务
- Slave Node 主要用来进行横向扩容,做读写分离,扩容的 Slave Node 可以提高读的吞吐量和并发量
如果使用主从架构,那么建议开启 Master Node 的持久化,因为可能有这种情况:Master 宕机重启,数据是空的,那么一经过复制,Slave Node 的数据也丢了
此外,还需要做 Master 的各自备份方案,因为本地所有文件丢失了,就可以从备份中条一份 RDB
去恢复 Master,这样确保启动的时候,是有数据的
2.2 原理
2.2.1 初次触发
初次触发,主要是全量复制的过程
- 启动一个 Slave Node,会发送一个
PSYNC
命令给 Master Node - Slave Node 初次连接到 Master Node,就会触发一次
full resynchronization
全量复制 - 此时 Master 会启动一个后台线程,开始生成一份
RDB
快照,同时还会从客户端 Client 接收到的所有写命令缓存在内存中 RDB
文件生成完毕,Master Node 会将这个快照发送给 Slave- Slave 会先写入本地磁盘,然后从本地磁盘加载到内存
- 接着 Master 会将内存中缓存的写命令发送到 Slave
- Slave 会同步这些数据
- Slave Node 如果跟 Master Node 有网络故障,断开了连接,会自动重连
- 连接之后 Master Node 仅会复制给 Slave 部分缺少的数据,这就是增量复制
2.2.2 断点续传
断点续传,主要是
Redis 2.8 开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制,而不是从头开始复制
Master 会在内存中维护一个 backlog
,Master 和 Slave 都会保存一个 replica offset
、Master Run ID
,而 replica offset
是保存在 backlog
中的
如果 M-S 网络连接断开,那么 slave 会让 master 从上次 replica offset
开始继续复制,如果没有找到对于的 offset
,就会执行一次 resynchronization
2.2.3 无持久化复制
Master 在内存中直接创建 RDB
,然后发送给 Slave,Master 不需要自己在本地落地磁盘了,只需要在配置文件中开启 repl-diskless-sync yes
即可
repl-diskless-sync yes
repl-diskless-sync-delay 5
2.2.4 过期 key 处理
Slave 不会淘汰过期 key,只会等待 Master 淘汰 Key,再同步给 Slave,此时,Master 是通过模拟一条 DEL 命令发送给 Slave 去淘汰的
2.3 实例
- Slave 启动,会在本地保存 Master 的信息,包括 Master 的
host、ip
- Slave 定时任务开始,每秒检查是否有新的 Master 要连接和复制
- 如果发现,就跟 Master 建立 Socket 网络连接,然后 Slave 发送
ping
命令给 Master - 如果 Master 设置了
requirepass
,那么 Slave 必须发送masterauth
口令过去认证 - Master 第一次执行全量复制,将数据复制给 Slave
- 后续 Master 持续将写命令,异步复制给 Slave
2.4 复制
2.4.1 全量复制
-
Master 执行
bdsave
,在本地生成一份RDB
快照 -
Master 将
RDB
快照文件发送给 Slave,如果RDB
复制时间超过 60 秒(repl-timeout
),那么 Slave 就会认为复制失败,这个参数可以适当调大,千兆网卡,每秒传输 100 MB,6 G 文件,很可能超过 60S -
Master 在生成
RDB
时,会将所有新的写命令缓存在内存中,在 Slave 保存了RDB
后,再将新的写命令复制给 Slave -
如果在复制期间,内存缓冲区持续消耗超过 64 MB,或者一次性超过 256 MB,那么停止复制,复制失败
参数可以设置:
client-output-buffer-limit slave 256MB 64MB 60
-
Slave 接收到
RDB
之后,清空自己的旧数据,然后重新加载RDB
到自己的内存中,同时基于旧的数据版本对外提供服务 -
如果 Slave 开启了
AOF
,那么会立即执行BGREWRITEAOF
,重写AOF
2.4.2 增量复制
- 全量复制过程中,M-S 网络中断,Slave 重新连接 Master,此时触发增量复制
- Master 直接从自己的
backlog
中获取部分丢失的数据,发送给 Slave Node,默认的backlog
就是 1 MB - Master 根据 Slave 发送的
psync
中的offset
来从backlog
中获取数据的
2.4.3 异步复制
Master 每次接收到写命令后,现在内部写入数据,然后异步发送给 Slave
2.5 心跳
主从节点,会互相发送心跳包,Master 默认每隔 10 秒发送一次心跳包,Slave 每隔 1 秒发送一个心跳包