写在前面
在实际生产环境中,单机Redis面临两个核心问题:性能瓶颈和单点故障。主从复制是Redis实现高可用的基础,它不仅解决了数据冗余备份问题,还为读写分离、故障转移提供了可能。今天我们深入理解Redis主从复制的原理与实践。

文章目录
-
- 写在前面
- 一、为什么需要主从复制?
-
- [1.1 单机Redis的局限性](#1.1 单机Redis的局限性)
- [1.2 主从复制的价值](#1.2 主从复制的价值)
- 二、主从复制原理
-
- [2.1 复制流程概述](#2.1 复制流程概述)
- [2.2 全量同步(SYNC)](#2.2 全量同步(SYNC))
- [2.3 部分同步(PSYNC)](#2.3 部分同步(PSYNC))
- [2.4 命令传播](#2.4 命令传播)
- 三、主从复制配置
-
- [3.1 配置方式](#3.1 配置方式)
- [3.2 重要配置参数](#3.2 重要配置参数)
- [3.3 查看复制状态](#3.3 查看复制状态)
- 四、主从切换
-
- [4.1 手动主从切换](#4.1 手动主从切换)
- [4.2 读写分离配置](#4.2 读写分离配置)
- 五、踩坑提醒
- 六、主从复制优化
-
- [6.1 配置优化](#6.1 配置优化)
- [6.2 架构优化](#6.2 架构优化)
- 七、面试高频考点
- 八、参考资料
- 九、互动话题
一、为什么需要主从复制?
1.1 单机Redis的局限性
实际场景:某电商平台Redis单机承载了100万QPS,在双十一大促时,CPU使用率达到100%,响应延迟从1ms飙升到100ms,严重影响了用户体验。
单机Redis面临的问题:
| 问题 | 说明 |
|---|---|
| 性能瓶颈 | 单机处理能力有限,无法水平扩展 |
| 单点故障 | 服务器宕机后服务不可用 |
| 数据丢失风险 | 硬件故障可能导致数据丢失 |
| 读写压力 | 所有请求都打到一台服务器 |
1.2 主从复制的价值
主从复制带来的好处:
-
数据冗余:实现数据热备份
-
读写分离:主节点写,从节点读,分担压力
-
高可用基础:为哨兵和集群提供基础
-
故障恢复:主节点故障时可切换到从节点
┌─────────────┐ │ Client │ └──────┬──────┘ │ Write ▼ ┌─────────────┐ │ Master │ │ (写+读) │ └──────┬──────┘ │ 复制 ┌─────────────┼─────────────┐ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Slave-1 │ │ Slave-2 │ │ Slave-3 │ │ (只读) │ │ (只读) │ │ (只读) │ └─────────────┘ └─────────────┘ └─────────────┘ ▲ ▲ ▲ │ │ │ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐ │ Read │ │ Read │ │ Read │ └─────────┘ └─────────┘ └─────────┘
二、主从复制原理
2.1 复制流程概述
经验之谈:理解复制流程对于排查主从同步问题至关重要,特别是全量同步和部分同步的区别。
Redis主从复制分为三个阶段:
- 连接建立阶段:从节点连接主节点
- 数据同步阶段:全量同步或部分同步
- 命令传播阶段:主节点持续发送写命令
2.2 全量同步(SYNC)
全量同步发生在:
- 从节点第一次连接主节点
- 从节点断开时间过长,无法部分同步
全量同步流程:
┌──────────────┐ ┌──────────────┐
│ Slave │ │ Master │
└──────┬───────┘ └──────┬───────┘
│ │
│ 1. PSYNC ? -1 │
│────────────────────────────────────────────>│
│ │
│ 2. FULLRESYNC <runid> <offset> │
│<────────────────────────────────────────────│
│ │
│ 3. 执行BGSAVE生成RDB │
│ (同时记录写命令到缓冲区) │
│ │
│ 4. 发送RDB文件 │
│<────────────────────────────────────────────│
│ │
│ 5. 加载RDB文件 │
│ │
│ 6. 发送缓冲区的写命令 │
│<────────────────────────────────────────────│
│ │
│ 7. 同步完成,开始命令传播 │
│ │
2.3 部分同步(PSYNC)
Redis 2.8引入部分同步,减少全量同步的开销。
部分同步条件:
- 从节点之前同步过主节点
- 主节点runid未变化
- 复制偏移量在复制缓冲区范围内
核心概念:
| 概念 | 说明 |
|---|---|
| runid | 主节点的唯一标识,每次重启会变化 |
| offset | 复制偏移量,记录同步位置 |
| repl_backlog_buffer | 复制缓冲区,环形结构,默认1MB |
┌─────────────────────────────────────────────────────────┐
│ repl_backlog_buffer │
│ ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐ │
│ │ cmd1│ cmd2│ cmd3│ cmd4│ cmd5│ cmd6│ cmd7│ cmd8│ ... │ │
│ └─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘ │
│ ▲ │
│ │ │
│ master_offset │
└─────────────────────────────────────────────────────────┘
如果 slave_offset 在缓冲区范围内,可以部分同步
2.4 命令传播
同步完成后,主节点持续将写命令发送给从节点:
redis
# 主节点执行写命令
SET key1 value1
# 主节点将命令传播给从节点
# 从节点执行相同的命令保持数据一致
三、主从复制配置
3.1 配置方式
方式一:配置文件
conf
# redis.conf(从节点配置)
replicaof 192.168.1.100 6379
# Redis 5.0之前使用
# slaveof 192.168.1.100 6379
# 从节点只读
replica-read-only yes
# 主节点密码
masterauth "your_password"
方式二:命令行
redis
# 在从节点执行
REPLICAOF 192.168.1.100 6379
# 取消主从关系
REPLICAOF NO ONE
3.2 重要配置参数
| 参数 | 说明 | 默认值 |
|---|---|---|
replicaof |
主节点地址和端口 | - |
masterauth |
主节点密码 | - |
replica-read-only |
从节点只读 | yes |
repl-diskless-sync |
无盘复制 | no |
repl-backlog-size |
复制缓冲区大小 | 1MB |
repl-timeout |
复制超时时间 | 60s |
repl-disable-tcp-nodelay |
禁用TCP_NODELAY | no |
3.3 查看复制状态
redis
# 查看主从复制信息
INFO replication
# 主节点返回示例
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.101,port=6379,state=online,offset=1024,lag=0
slave1:ip=192.168.1.102,port=6379,state=online,offset=1024,lag=0
master_repl_offset:1024
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1024
# 从节点返回示例
# Replication
role:slave
master_host:192.168.1.100
master_port:6379
master_link_status:up
slave_repl_offset:1024
四、主从切换
4.1 手动主从切换
踩坑提醒:手动切换需要谨慎操作,确保数据同步完成后再切换,否则可能丢失数据。
步骤:
redis
# 1. 在新主节点执行,停止复制
REPLICAOF NO ONE
# 2. 在其他从节点执行,指向新主节点
REPLICAOF new_master_ip 6379
# 3. 验证主从状态
INFO replication
4.2 读写分离配置
应用层需要区分读写请求:
shell
# 主节点地址(写操作)
MASTER_HOST=192.168.1.100
MASTER_PORT=6379
# 从节点地址(读操作)
SLAVE_HOSTS=192.168.1.101:6379,192.168.1.102:6379
读写分离架构:
┌─────────────┐
│ Application │
└──────┬──────┘
│
▼
┌─────────────┐
│ 读写分离层 │
│ (客户端/代理) │
└──────┬──────┘
│
┌───┴───┐
│ │
▼ ▼
Write Read
│ │
▼ ▼
Master Slave
五、踩坑提醒
踩坑提醒:复制延迟问题
问题描述:
主从复制是异步的,从节点的数据可能落后于主节点,读取从节点可能获取到过期数据。
延迟产生原因:
- 网络延迟
- 从节点性能不足
- 主节点写入压力过大
- 大key复制耗时
解决方案:
| 方案 | 说明 |
|---|---|
| 监控延迟 | 使用INFO replication查看lag值 |
| 读写分离策略 | 强一致性读走主节点 |
| 优化网络 | 使用内网、万兆网卡 |
| 控制大key | 避免存储大key |
| 增加带宽 | 提高复制带宽限制 |
conf
# 调整复制带宽限制
repl-backlog-size 64mb # 增大复制缓冲区
client-output-buffer-limit replica 256mb 64mb 60
踩坑提醒:主从切换数据丢失
问题描述:
异步复制场景下,主节点宕机时,从节点可能还没收到最新的写命令。
解决方案:
- 配置合理的
min-replicas-to-write - 使用哨兵或集群实现自动故障转移
- 业务层实现重试机制
conf
# 至少有1个从节点才能写入
min-replicas-to-write 1
min-replicas-max-lag 10
踩坑提醒:全量同步阻塞
问题描述:
主节点执行BGSAVE生成RDB时,如果内存数据量大,会消耗大量CPU和内存,影响性能。
解决方案:
- 使用无盘复制
- 控制单实例内存大小
- 在低峰期添加从节点
conf
# 开启无盘复制
repl-diskless-sync yes
repl-diskless-sync-delay 5
六、主从复制优化
6.1 配置优化
conf
# 增大复制缓冲区
repl-backlog-size 256mb
# 开启无盘复制
repl-diskless-sync yes
# 复制超时时间
repl-timeout 120
# 从节点TCP_NODELAY
repl-disable-tcp-nodelay no
# 限制复制缓冲区大小
client-output-buffer-limit replica 512mb 128mb 60
6.2 架构优化
| 优化项 | 说明 |
|---|---|
| 主从节点同机房 | 减少网络延迟 |
| 从节点不少于2个 | 保证数据冗余 |
| 合理分配内存 | 预留内存给复制 |
| 监控复制延迟 | 及时发现问题 |
七、面试高频考点
考点1:主从复制的流程?
答案:
- 连接建立:从节点连接主节点,发送PSYNC命令
- 全量同步:主节点执行BGSAVE生成RDB,发送给从节点
- 缓冲同步:主节点将同步期间的写命令发送给从节点
- 命令传播:主节点持续将写命令发送给从节点
PSYNC优化:
- 从节点记录runid和offset
- 重连时发送PSYNC runid offset
- 如果offset在缓冲区范围内,只同步增量数据
考点2:如何减少主从复制延迟?
答案:
- 网络优化:主从部署在同机房,使用高速网络
- 配置优化:增大复制缓冲区,开启无盘复制
- 架构优化:控制单实例内存,避免大key
- 监控告警 :监控
slave_repl_offset和master_repl_offset差值 - 读写策略:强一致性读走主节点
考点3:主从复制是同步还是异步?
答案:
Redis主从复制是异步的:
- 主节点执行写命令后立即返回,不等待从节点确认
- 通过
repl_backlog_buffer记录写命令 - 从节点异步获取并执行写命令
影响:
- 优点:主节点性能不受从节点影响
- 缺点:主节点宕机可能丢失未同步的数据
考点4:SYNC和PSYNC的区别?
答案:
| 对比项 | SYNC | PSYNC |
|---|---|---|
| Redis版本 | 2.8之前 | 2.8之后 |
| 同步方式 | 只支持全量同步 | 支持全量和部分同步 |
| 断线重连 | 需要全量同步 | 可能只需部分同步 |
| 性能 | 低 | 高 |
| 资源消耗 | 高 | 低 |
八、参考资料
九、互动话题
- 你的生产环境主从架构是如何设计的?遇到过什么问题?
- 如何监控主从复制延迟?延迟超过多少需要告警?
- 主节点宕机后,如何实现自动故障转移?
欢迎在评论区分享你的经验和见解!
下一期预告:Day10 - Redis哨兵机制,敬请期待!