一、前言:为什么主从断连后能快速恢复?
在 Redis 主从架构中,你是否曾好奇:
当从节点(slave)因网络抖动短暂断开后,为何能快速追上主节点(master)的数据,而无需全量同步(RDB)?
答案就在于 Redis 4.0 引入并优化的核心机制 ------ repl_backlog(复制积压缓冲区)。
本文将带你:
✅ 深入 repl_backlog 的内存结构与工作原理
✅ 理解 PSYNC(部分重同步) 如何依赖它
✅ 掌握参数调优与故障排查方法
✅ 避免"主从全量同步风暴"导致服务雪崩
二、主从复制演进:从 SYNC 到 PSYNC
2.1 Redis 2.8 之前:SYNC(全量同步)
- 从节点断连 → 重新连接 → 主节点生成 RDB 快照 → 全量传输
- 问题:RDB 生成耗 CPU/IO,大实例同步慢(分钟级),带宽打满
2.2 Redis 2.8+:PSYNC(部分重同步)
- 支持 Partial Resynchronization(部分重同步)
- 核心依赖两个机制:
replication ID + offset:唯一标识主从复制流repl_backlog:主节点维护的环形缓冲区,保存最近写命令
✅ 效果:从节点断连 10 秒后重连,只需同步断连期间的命令,毫秒级恢复!
三、repl_backlog 是什么?
3.1 定义
repl_backlog 是主节点在内存中维护的一个固定大小的环形缓冲区(circular buffer) ,用于存储最近执行的写命令(以 replication offset 为索引)。
3.2 核心作用
为断连的从节点提供"命令回溯"能力,避免全量同步
3.3 数据结构示意图
主节点 repl_backlog(环形缓冲区)
┌───────────┬───────────┬───────────┬───────────┐
│ cmd@1001 │ cmd@1002 │ cmd@1003 │ cmd@1004 │ ← 写入指针 (master_repl_offset)
└───────────┴───────────┴───────────┴───────────┘
↑
backlog 起始偏移 (repl_backlog_histlen)
- 当缓冲区写满,旧命令被新命令覆盖(环形)
- 每个从节点记录自己最后同步的
offset - 重连时,从节点上报
replication ID + offset,主节点判断是否在repl_backlog范围内
四、PSYNC 工作流程详解
4.1 正常同步流程
- 从节点启动,发送
PSYNC ? -1(首次同步) - 主节点返回
FULLRESYNC <replication_id> <offset> - 主节点生成 RDB 并传输,之后持续发送写命令
4.2 断连后重连(部分重同步)
- 从节点断连(如网络抖动 5 秒)
- 重连后发送
PSYNC <replication_id> <last_offset>(如 offset=1000) - 主节点检查:
replication_id是否匹配(防止主节点重启)last_offset是否 ≥repl_backlog_start(即命令还在缓冲区中)
- 若满足 → 返回
+CONTINUE,并从repl_backlog中提取offset+1开始的命令发送 - 从节点接收命令并执行,完成同步
4.3 何时会触发全量同步?
以下任一条件成立,将 fallback 到 FULLRESYNC:
replication ID不匹配(主节点重启,ID 变更)- 从节点的
offset<repl_backlog_start(命令已被覆盖) repl_backlog被关闭(repl-backlog-size = 0)
五、关键配置参数解析
| 参数 | 默认值 | 说明 |
|---|---|---|
repl-backlog-size |
1MB | repl_backlog 缓冲区大小 |
repl-backlog-ttl |
3600 秒 | 主节点无从节点时,缓冲区保留时间(0=永久保留) |
5.1 如何计算合理的 repl-backlog-size?
公式:
repl-backlog-size ≥ max(网络中断容忍时间 × 主节点写入吞吐量, 1MB)
举例:
- 业务可容忍从节点断连 5 分钟
- 主节点写入峰值:10 MB/s
- 则所需缓冲区 ≥ 5 × 60 × 10 = 3000 MB
💡 建议:
- 小型实例:默认 1~10MB 足够
- 高写入场景:设为 100MB~1GB+
- 多从节点环境:缓冲区由所有从节点共享,按最慢从节点计算
5.2 查看 repl_backlog 状态
bash
127.0.0.1:6379> INFO REPLICATION
# Replication
role:master
connected_slaves:2
...
master_repl_offset:15000
repl_backlog_active:1
repl_backlog_size:1048576 # 1MB
repl_backlog_first_byte_offset:14000 # 缓冲区起始 offset
repl_backlog_histlen:1001 # 缓冲区实际数据长度
repl_backlog_first_byte_offset = master_repl_offset - repl_backlog_histlen + 1- 从节点 offset 必须 ≥
repl_backlog_first_byte_offset才能部分同步
六、实战:模拟断连与恢复
6.1 场景:从节点断连 10 秒
bash
# 主节点写入大量数据(模拟高负载)
while true; do redis-cli INCR counter; done
# 从节点断网(停 10 秒)
systemctl stop network
# 恢复网络
systemctl start network
6.2 观察日志
从节点日志:
* Reconnecting to MASTER 192.168.1.100:6379 after failure
* MASTER <-> REPLICA sync started
* Non blocking connect for SYNC fired the event.
* Master replied to PING
* Partial resynchronization request accepted. Sending reply.
* Successful partial resynchronization with master.
✅ 出现 Partial resynchronization 表示成功使用 repl_backlog
6.3 若缓冲区太小?
若 repl-backlog-size 过小,日志将显示:
* Full resync requested by slave.
* Starting BGSAVE for SYNC with target: disk
→ 触发全量同步,服务可能卡顿!
七、生产环境最佳实践
✅ 1. 合理设置 repl-backlog-size
- 监控主节点写入速率(
INFO MEMORY+master_repl_offset变化) - 按 最大可容忍断连时间 × 写入速率 × 1.5 安全系数 设置
✅ 2. 避免主节点频繁重启
- 主节点重启会生成新的
replication ID,导致所有从节点全量同步 - 使用 Redis Sentinel 或 Cluster 实现故障自动转移,而非直接重启主库
✅ 3. 监控关键指标
master_repl_offset增长速度repl_backlog_histlen是否接近repl_backlog_size- 从节点
lag(延迟)
✅ 4. 多从节点场景
- 所有从节点共享同一个
repl_backlog - 同步最慢的从节点决定了缓冲区最小保留范围
- 避免"慢从节点"拖垮主节点内存
八、常见误区澄清
❌ 误区 1:repl_backlog 是每个从节点独立的
正解:全局唯一,所有从节点共享同一个环形缓冲区
❌ 误区 2:repl_backlog 存储的是 RDB 数据
正解 :存储的是 写命令(如 SET、HSET)的原始协议数据,非 RDB
❌ 误区 3:增大 repl-backlog-size 会显著增加内存
正解 :是固定大小环形缓冲区,内存占用 =
repl-backlog-size,可控
九、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!