高级篇 09. 分布式缓存 - 增量同步原理与 repl_baklog

5 阅读5分钟

在真实的网络环境中,机房的网络抖动简直是家常便饭。如果小弟(Slave)仅仅因为网络波动断开了 3 秒钟,再次连上时,大哥(Master)如果还要傻乎乎地去执行 bgsave,把几 GB 的全量数据重新发一遍,这不仅会瞬间榨干大哥的 CPU 和网络带宽,还会导致整个 Java 后端系统的响应极度卡顿。

为了优雅地解决这种“短暂掉线重连”的问题,Redis 设计了被誉为神来之笔的增量同步机制。这也是在后端研发面试中,考查你对高可用容灾架构理解深度的绝对核心题。


📚 高级篇 09. 分布式缓存 - 增量同步原理与 repl_baklog

一、 核心场景:什么时候会触发增量同步?

增量同步(Partial Resynchronization)只发生在一个特定的场景下:从节点(Slave)曾经和主节点(Master)同步过数据,但由于网络原因短暂断开,随后又迅速重新连接上了主节点。

此时,Slave 内存里已经有了绝大部分的老数据,它缺少的仅仅是断线这短短几秒钟内,Master 接收到的新命令。


二、 破局神器:环形的 repl_baklog 缓冲区

要想只把“断线期间”的数据补发给 Slave,Master 就必须有一个地方把最近执行过的写命令存起来。这个神奇的地方就是 repl_baklog (复制积压缓冲区)

🌟 repl_baklog 的三大核心特质(面试必考):

  1. 它是一个固定大小的数组: 默认大小通常只有 1MB。
  2. 它是一个“环形”缓冲区: 就像一个圆形的操场跑道。当数据写满 1MB 跑到尽头时,它会从头开始覆盖最老的数据。
  3. 它记录了偏移量 (offset): 操场跑道上布满了刻度(就是 offset)。Master 每写入一个字节的命令,它的指针就往前走一格;Slave 每拉取走一个字节的命令,它的指针也跟着往前走一格。

三、 增量同步的核心执行流程

当短暂掉线的 Slave 重新连上 Master 时,激动人心的对暗号过程开始了:

  1. 小弟呈递旧令牌: Slave 向 Master 发送 psync <大哥的replid> <自己的offset>

    • 这次它发的不再是 ?-1 了,而是:“大哥,我还是之前跟你混的那个小弟(拿着你的 replid),我掉线前抄笔记抄到了 offset 这个位置,请把后面的补给我。”
  2. 大哥验明正身: Master 收到命令,对比一下 replid,发现确实是自己的亲小弟。

  3. 大哥检查进度条(最关键的一步): Master 去环形的 repl_baklog 里看一眼。

    • 如果 Slave 的 offset 还在这个环里: 说明小弟掉线时间很短,缺少的命令还在缓冲区里没被覆盖。Master 立刻回复 +CONTINUE(准许增量同步!)。
    • 如果 Slave 的 offset 已经被覆盖了: 说明小弟掉线太久了,旧数据已经被 Master 跑了好几圈的新数据洗掉了。此时,Master 只能无奈地回复 +FULLRESYNC,强行退化为全量同步
  4. 发送补偿数据: 如果是 +CONTINUE,Master 会极其高效地把 repl_baklog 中从 Slave offset 一直到当前 Master offset 之间的这一小段增量命令,打包发送给 Slave。

  5. 小弟执行追赶: Slave 拿到这一小撮命令,在内存中飞速重放,瞬间追平大哥的进度!


四、 面试绝杀技:如何避免增量同步退化为全量同步?

在大型系统的架构演进中,面试官极度喜欢问这个场景题:

🗣️ 面试官发难: “如果你们的 Redis 集群因为网络割接,Slave 断开了 2 分钟。连上之后,发现触发了全量同步,导致 Master 压力骤增,引发了线上报警。请问你作为研发工程师,该如何优化和彻底解决这个问题?”

💡 你的满分优化方案:

“导致增量同步失败、退化为全量同步的根本原因,是 Slave 掉线的时间过长,导致它的 offset 在环形缓冲区 repl_baklog 中被 Master 的新数据覆盖了。

要解决这个问题,核心思路就是延长新数据覆盖老数据的时间差

redis.conf 中,有一个极其重要的配置项:repl-backlog-size(默认 1MB)。

我们需要根据业务的真实写入 QPS预估的最大网络断线时长来重新计算这个值。

计算公式: 缓冲空间大小 = Master 每秒平均写入的数据量(Byte) * 预估的最长断线容忍时间(秒) * 2 (冗余系数)

例如,如果 Master 每秒写入大约 1MB 的命令数据,我们希望容忍最长 1 分钟的网络断线。那么我们应该将 repl-backlog-size 优化修改为 1MB * 60秒 * 2 = 120MB 左右。这样就能在绝大多数网络抖动场景下,完美保证集群走极其轻量的增量同步机制,避免全量快照带来的性能雪崩!”


学习总结

至此,Redis 主从复制的底层数据流转机制(全量 + 增量),你已经拥有了极其通透的理解。

在这个主从架构下,我们的数据有了备份,读并发也有了极大的提升。但是,一个最要命的问题还没有解决:

如果带头大哥(Master)的主板突然烧了,彻底宕机了,整个集群就失去了唯一的写入口。那些小弟们只会傻傻地等着大哥复活,没人敢主动站出来当新大哥!

这也就意味着,我们的系统在写操作上,依然存在致命的单点故障风险

准备好进入分布式缓存的第三关,去见识一下能够实现 7x24 小时无人值守、自动选拔新大哥的终极高可用组件——**“10. 分布式缓存 - 哨兵机制 (Sentinel) 的原理与架构”**了吗?