这是《Redis 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 复制是高可用的基础:从节点提供副本,读写分离,并为故障切换和备份服务。本章讲全量同步、增量同步、复制积压缓冲、replid 与常见问题。
17.1 复制的角色
Master
|- Replica A
|- Replica B
配置:
# Replica
replicaof 192.168.1.10 6379
masterauth password
replica-read-only yes
查看:
INFO replication
ROLE
主节点关键信息:
role:master
connected_slaves:2
slave0:ip=...,port=...,state=online,offset=...
master_replid:...
master_repl_offset:...
17.2 复制是异步的
主节点执行写命令后:
1. 本地执行
2. 返回客户端
3. 异步传播给 replica
不是等从节点确认后才返回。因此:
- 主节点写入成功不代表从节点已收到;
- 主节点崩溃时,未同步写可能丢失;
- 读从节点可能读到旧数据。
这是性能与一致性的核心取舍。
17.3 全量同步流程
Replica Master
| --- PSYNC ? -1 ----------> |
| 判断无法增量同步
| <--- +FULLRESYNC replid offset
| BGSAVE 生成 RDB
| <--- RDB 数据 -------------
| 加载 RDB
| <--- 缓冲期间写命令 --------
| 追上 offset
| --- PSYNC replid offset -> |
| 进入命令流同步
触发场景:
- 从节点第一次连接;
- 复制 ID 无法匹配;
- offset 已不在复制积压缓冲;
- 主节点认为无法安全增量同步。
全量同步成本高:
- 主节点 BGSAVE;
- 网络传输全量 RDB;
- 从节点加载;
- 主节点缓存同步期间写命令。
17.4 增量同步
从节点断线重连后发送:
PSYNC <replid> <offset>
如果 offset 仍在主节点复制积压缓冲区内,只同步缺失命令:
Master -> CONTINUE
-> 发送 offset 之后的数据
配置:
repl-backlog-size 256mb
repl-backlog-ttl 3600
估算:
backlog >= 断线时长(s) * 主节点写流量(MB/s)
例:平均写 20MB/s,目标容忍 60s 断线
-> 至少 1.2GB
17.5 replid 与 second replid
每个主实例有复制 ID(replid),配合 offset 标识数据版本。
故障切换后:
旧 Master: replid=A, offset=1000
Replica 提升为新 Master:
新 replid=B
second_replid=A
second_replid_offset=1000
其他从节点如果还属于旧数据链,可通过 second replid 判断是否能部分重同步,减少全量同步概率。
17.6 复制缓冲区
主节点为每个 replica 维护输出缓冲:
client-output-buffer-limit replica 256mb 64mb 60
repl-timeout 60
如果从节点消费慢:
- 主节点输出缓冲堆积;
- 内存增长;
- 超过限制断开 replica;
- 重连后可能触发全量同步,形成恶性循环。
大 key、网络抖动、从节点磁盘/性能瓶颈都会放大这个问题。
17.7 读写分离与一致性
从节点默认只读:
replica-read-only yes
读写分离方案:
写 -> Master
读 -> Replica
优点:分摊读流量。风险:
- 复制延迟导致读到旧值;
- 主从切换后可能读到更旧数据;
- 会话状态对一致性敏感时出错。
适合:排行榜、商品缓存、统计类读。
不适合:支付后立即查状态、权限变更、库存强一致判断。
17.8 复制延迟监控
INFO replication
关注:
| 字段 | 含义 |
|---|---|
master_repl_offset |
主节点复制偏移 |
slave0:...offset |
从节点已同步偏移 |
master_link_status |
从节点连接状态 |
master_last_io_seconds_ago |
最近主从 IO |
slave_read_repl_offset |
从节点读偏移 |
计算延迟:
lag = master_repl_offset - replica_offset
offset 差是字节数,不等于时间;可以结合时间序列监控增长趋势。
17.9 无盘复制
repl-diskless-sync no
repl-diskless-sync-delay 5
开启后,主节点不落 RDB 文件,而是直接通过网络发送给 replica。
适合:
- 磁盘慢;
- 磁盘空间紧张;
- 多个从节点同时同步;
- 网络与内存资源充足。
风险:占用主节点 CPU/网络,且不产生本地 RDB 备份。
17.10 常见复制问题
| 问题 | 原因 | 处理 |
|---|---|---|
| 频繁全量同步 | backlog 小、网络断、缓冲超限 | 增大 backlog,修网络 |
| 从节点内存上涨 | 加载 RDB + 缓冲数据 | 控制实例大小,错峰同步 |
| 复制延迟持续增长 | 主写流量高、从节点慢 | 优化写、拆实例、扩容 |
MASTERDOWN |
主不可达 | 检查网络/主健康,配合哨兵 |
| 从节点数据落后业务读失败 | 读写分离 | 强一致读走主或业务版本校验 |
17.11 生产建议
一主两从起步;
repl-backlog 按写流量与目标断线时间估算;
从节点作为备份执行 BGSAVE;
监控 offset 差和连接状态;
避免把延迟敏感业务读到从节点;
为哨兵或 Cluster 预留故障切换方案。
本章小结
- Redis 复制默认异步,主写入成功不等从确认;
- 首次或无法部分重同步时执行全量 RDB;
- replid + offset 决定能否增量同步;
- backlog 大小按写流量与断线容忍时间估算;
- 从节点消费慢会堆积复制输出缓冲;
- 读写分离必须评估业务对延迟的容忍度。
思考题
- 主从复制能保证数据不丢吗?为什么?
- 从节点断线 30 秒,写流量 50MB/s,backlog 应至少多大?
- 为什么读从节点可能读到逻辑上已过期的数据?业务如何防护?