在真实的网络环境中,机房的网络抖动简直是家常便饭。如果小弟(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 的三大核心特质(面试必考):
- 它是一个固定大小的数组: 默认大小通常只有 1MB。
- 它是一个“环形”缓冲区: 就像一个圆形的操场跑道。当数据写满 1MB 跑到尽头时,它会从头开始覆盖最老的数据。
- 它记录了偏移量 (
offset): 操场跑道上布满了刻度(就是offset)。Master 每写入一个字节的命令,它的指针就往前走一格;Slave 每拉取走一个字节的命令,它的指针也跟着往前走一格。
三、 增量同步的核心执行流程
当短暂掉线的 Slave 重新连上 Master 时,激动人心的对暗号过程开始了:
-
小弟呈递旧令牌: Slave 向 Master 发送
psync <大哥的replid> <自己的offset>。- 这次它发的不再是
?和-1了,而是:“大哥,我还是之前跟你混的那个小弟(拿着你的replid),我掉线前抄笔记抄到了offset这个位置,请把后面的补给我。”
- 这次它发的不再是
-
大哥验明正身: Master 收到命令,对比一下
replid,发现确实是自己的亲小弟。 -
大哥检查进度条(最关键的一步): Master 去环形的
repl_baklog里看一眼。- 如果 Slave 的
offset还在这个环里: 说明小弟掉线时间很短,缺少的命令还在缓冲区里没被覆盖。Master 立刻回复+CONTINUE(准许增量同步!)。 - 如果 Slave 的
offset已经被覆盖了: 说明小弟掉线太久了,旧数据已经被 Master 跑了好几圈的新数据洗掉了。此时,Master 只能无奈地回复+FULLRESYNC,强行退化为全量同步!
- 如果 Slave 的
-
发送补偿数据: 如果是
+CONTINUE,Master 会极其高效地把repl_baklog中从 Slaveoffset一直到当前 Masteroffset之间的这一小段增量命令,打包发送给 Slave。 -
小弟执行追赶: 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) 的原理与架构”**了吗?