Redis - 主从架构

294

一、主从架构

单机 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 offsetMaster 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 秒发送一个心跳包