redis 集群

主从复制

为了避免单点故障,redis提供了 主从复制功能

保证服务器 数据一致性,且主从服务器之间采用 「读写分离」 方式
读写分离

第一次同步

使用 replicaof 命令形成主服务器和从服务器关系

比如

1
2
# 服务器 B 执行这条命令,成为 A 的从服务器
replicaof <服务器 A 的 IP 地址> <服务器 A 的 redis 端口号>

主从服务器第一次同步过程分为三个阶段

  • 建立连接、协商同步
  • 主服务器同步数据给从服务器
  • 主服务器发送新写操作命令给从服务器

建立连接、协商同步

执行了 replicaof 后,从服务器会给主服务器发送 psync 命令,表示数据同步

psync 命令包含两个参数, 主服务器的 runID复制进度 offset

  • runID,每个redis在启动时会产生一个随机的ID用来唯一标识自己
  • offset,表示复制进度,第一次同步时,值为 -1

主服务器收到 psync 命令后,会用 FULLRESYNC 作为响应返回给对方

FULLRESYNC 也携带两个参数: 主进程的 runID 和 主服务器目前的复制进度 offset

FULLRESYNC 响应命令 采用 全量复制 的方式

主服务器同步数据给从服务器

主服务器会执行 bgsave 来生成 RDB 文件,然后把文件发送给从服务器

从服务器收到 RDB 文件后,会清空数据库,然后载入 RDB 文件

这里在主服务器上执行 bgsave 的期间,如果执行写操作,记录不会记录到刚刚生成的 RDB 文件中,这时主从服务器间数据不一致

为了保证主从服务器数据一致性, 主服务器在下面这三个时间间隙收到的写操作命令,写入到 replication buffer 缓冲区

  • 主服务器生成 RDB 文件期间
  • 主服务器发送 RDB 文件给从服务器期间
  • 「从服务器」加载 RDB 文件期间

主服务器发送新写操作命令给从服务器

完成 RDB 的载入后,从服务器会回复一个确认消息给主服务器

接着主服务器将 replication buffer 缓冲区中读取命令,发送给从服务器,来保证数据一致性

命令传播

主从服务器在完成第一次同步后,双方维护一个 TCP 长连接

后续主服务器通过连接将写操作命令发送给从服务器,维持数据一致性

增量复制

当主从服务器连接断开,客户端可能从 「从服务器」读到旧数据

如果此时断开的网络,又恢复正常,如何保证主从服务器数据一致性

redis 2.8 之前,会进行全量复制,即重新执行一次主从服务器第一次同步过程

redis 2.8 开始,主从服务器采用 增量复制 的方式继续同步,三个步骤

  • 恢复连接后,从服务器发送 psync 给主服务器,此时 offset 不为 -1
  • 主服务器收到命令后,用 CONTINUE 响应,采用增量复制的方式同步数据
  • 主服务器从主从服务器断开期间,所执行的写命令发送给从服务器执行

主服务器怎么知道要将哪些增量数据发送给从服务器?

  • repli_backlog_buffer 是一个 「环形」缓冲区
  • replication offset 标记上面那个缓冲区的同步进度,主从服务器有各自的偏移量,主服务器使用 master_repl_offset 标记自己的「写」,从服务器使用 slave_repl_offset 来标记自己「读」到的位置

在主服务器进行命令传播时,会将写命令发送给从服务器,也会写入到 repli_backlog_buffer 缓冲区中

重连后,从服务器将自己的偏移量 offset 发送给主服务器

  • 如果偏移量在 repl_backlog_buffer 缓冲区里,采用 增量复制
  • 如果不在,则采用 全量同步

为避免频繁使用全量同步,应该调整 repl-backlog-size 参数,默认为 1M

1
2
3
4
# 通过命令修改
CONFIG SET repl-backlog-size 2mb
# 通过配置文件修改
repl-backlog-size 2mb

面试题

如何判断 redis 某个节点是否正常工作

主节点每隔 10 秒

从节点每隔 1 秒

主从复制架构中,过期 key 如何处理

redis 是同步复制还是异步复制

主从复制中两个 Buffer(replication buffer 和 repl-backlog-size)有什么区别

如何应对主从数据不一致

为什么会出现主从不一致?

如何应对主从不一致

主从切换如何减少数据丢失

主从切换,产生数据丢失的情况有两种

  • 异步复制同步丢失
  • 集群产生脑裂数据丢失

我们不可能保证数据完全不丢失,只能做到使得尽量少的数据丢失

异步复制同步丢失

对于 redis 主节点与从节点之间的数据复制,是「异步复制」的,当客户端发送写请求给主节点,客户端会返回 ok ,主节点将写请求 异步 同步给各个从节点,但如果主节点还没来得及同步发生了断电,主节点内存的数据会丢失

减少异步复制的数据丢失方案

redis 配置中 min-slaves-max-lag ,表示一旦所有从节点数据复制和同步的延迟超过了 min-slaves-max-lag 值,主节点就会停止接受写请求,直到所有从节点数据同步完成

假设将 min-slaves-max-lag 设置为 5,那么当所有从节点数据复制和同步的延迟都超过 5 秒,就会认为 master 未来宕机后损失的数据会很多,拒绝写入新请求,这样 master 和 slave 数据差控制在 5 秒内,可以减少数据丢失

对于客户端,当发现不可写后,可以降级处理,先将数据写入本地缓存和磁盘,等恢复后再写入 master ;也可以写入消息队列,隔一段时间消费消息,重新写入

集群产生脑裂数据丢失

由于网络波动,集群节点间失去联系,主从数据不同步;重新选举主节点,将原来的主节点数据清空作为从节点,这导致原来的主节点的「断开期间的写操作」数据丢失

减少脑裂数据丢失

  • min-slaves-to-write x,主节点必须 至少 x 个从节点连接,否则禁止写数据
  • min-slaves-max-lag x,数据复制和同步的延迟 不能超过 x 秒,否则禁止写入

主从切换

redis 哨兵机制…