当前位置: 首页 > news >正文

Redis基础:5. 主从复制

Redis 主从复制:从单机孤胆到集群作战

一台 Redis 挂了怎么办?没关系,我们还有千千万万台!

想象一下这个场景:你的 Redis 单机跑得好好的,每天处理千万级请求。突然某个深夜,服务器内存坏了,Redis 进程崩溃。你的监控系统疯狂报警,用户开始反馈页面加载失败——因为所有缓存都丢了,数据库被活活打死。

你从睡梦中惊醒,手忙脚乱地重启 Redis。但恢复数据需要时间,这十分钟里,公司损失了多少钱?

单点故障,是每个架构师的噩梦。

今天我们就来聊聊如何让 Redis 从"孤胆英雄"变成"复仇者联盟"——主从复制


一、 什么是主从复制?为什么要用?

1.1 一句话定义

主从复制(Replication):将一台 Redis 服务器的数据,自动同步到其他多台 Redis 服务器。前者叫Master(主节点),后者叫Slave/Replica(从节点)

1.2 三大核心价值

价值说明场景
高可用Master 挂了,Slave 可以顶上去避免单点故障
读写分离Master 写,Slave 读提高吞吐量
数据备份Slave 可以作为热备份防止数据丢失

真实案例

  • 某电商网站在双十一期间,读 QPS 达到 50 万+。单机 Redis 绝对扛不住,但1 主 5 从,把读请求分散到 5 台 Slave 上,轻松应对。
  • 某社交平台,Master 突然宕机。哨兵(Sentinel)在 10 秒内自动把 Slave 提升为 Master,用户几乎无感知。

二、 主从复制的核心原理

2.1 三大阶段

主从复制分为三个阶段:建立连接 → 全量同步 → 增量同步

  1. 建立连接
    Slave → Master: PSYNC ? -1
    Master → Slave: +FULLRESYNC
  2. 全量同步(第一次或 offset 太落后)
    Master: BGSAVE 生成 RDB
    Master → Slave: 发送 RDB 文件
    Slave: 清空旧数据,加载 RDB
  3. 增量同步(正常运行中)
    Master: 将写命令写入 replication buffer
    Master → Slave: 持续发送写命令
    Slave: 执行写命令,保持同步

2.2 全量同步(Full Synchronization)

触发条件

  • Slave 第一次连接 Master
  • Slave 的复制 offset 落后太多(Master 的 backlog 已覆盖不到)
  • 执行了SLAVEOF NO ONE后重新配置

详细流程

# Step 1: Slave 发送 PSYNC 命令Slave: PSYNC ?-1# Step 2: Master 返回 FULLRESYNCMaster: +FULLRESYNC<master_replid><offset># Step 3: Master 执行 BGSAVE,生成 RDB 快照Master: BGSAVE (fork 子进程)# Step 4: Master 把 RDB 文件发送给 SlaveMaster → Slave: RDB 文件(二进制)# Step 5: Slave 清空旧数据,加载 RDBSlave: FLUSHALL Slave: 加载 RDB 到内存# Step 6: Master 把 RDB 生成期间的写命令发给 SlaveMaster → Slave: replication buffer 中的命令# Step 7: Slave 执行这些命令,追上 Master

注意:全量同步非常耗时!如果 RDB 文件有 10GB,网络传输 + 加载可能需要几分钟。期间 Slave 无法提供服务。

2.3 增量同步(Partial Synchronization)

Redis 2.8 引入了部分同步,解决了网络闪断后必须全量同步的低效问题。

核心机制

  • Master 维护一个replication backlog(环形缓冲区,默认 1MB)
  • 所有写命令同时写入 backlog
  • Slave 断线重连后,发送PSYNC <runid> <offset>
  • Master 检查 offset 是否还在 backlog 中
    • ✅ 如果在:发送+CONTINUE,然后发送 backlog 中的增量命令
    • ❌ 如果不在:退化为全量同步
┌─────────────────────────────────────┐ │ Master Replication Backlog │ │ (环形缓冲区,默认 1MB) │ ├─────────────────────────────────────┤ │ [cmd1][cmd2][cmd3]...[cmdN] │ │ ↑ ↑ │ │ Slave offset Master offset │ └─────────────────────────────────────┘

配置建议

# redis.conf # 增大 backlog,避免网络抖动导致全量同步 repl-backlog-size 100mb # 在没有 Slave 的情况下,多久释放 backlog(0 = 永不释放) repl-backlog-ttl 3600

三、 环境搭建:从零开始配置主从

3.1 快速搭建(3 台机器,或者 1 台机器 3 个端口)

方案一:3 台物理机

  • Master:192.168.1.100:6379
  • Slave1:192.168.1.101:6379
  • Slave2:192.168.1.102:6379

方案二:单机 3 个实例(演示用)

# 1. 创建三个配置文件cpredis.conf redis-6379.confcpredis.conf redis-6380.confcpredis.conf redis-6381.conf
# redis-6379.conf(Master) port 6379 daemonize yes pidfile /var/run/redis-6379.pid logfile /var/log/redis-6379.log dir /var/lib/redis-6379 # redis-6380.conf(Slave) port 6380 daemonize yes pidfile /var/run/redis-6380.pid logfile /var/log/redis-6380.log dir /var/lib/redis-6380 # 关键配置:指定 Master replicaof 127.0.0.1 6379 # redis-6381.conf(Slave) port 6381 daemonize yes pidfile /var/run/redis-6381.pid logfile /var/log/redis-6381.log dir /var/lib/redis-6381 replicaof 127.0.0.1 6379
# 2. 启动三个实例redis-server redis-6379.conf redis-server redis-6380.conf redis-server redis-6381.conf# 3. 验证主从关系redis-cli-p6379INFO replication

3.2 动态配置(不停机添加从库)

# 在 Slave 上执行redis-cli-p6380127.0.0.1:6380>REPLICAOF127.0.0.16379OK# 取消复制(Slave 变 Master)127.0.0.1:6380>REPLICAOF NO ONE OK

3.3 验证主从同步

# 在 Master 上写数据redis-cli-p6379SET name"Redis Master"OK# 在 Slave 上读取redis-cli-p6380GET name"Redis Master"# 在 Slave 上尝试写(应该失败)redis-cli-p6380SET age18(error)READONLY You can'twriteagainst areadonly replica.

四、 核心配置参数详解

4.1 Master 配置

# 主从复制相关配置(在 Master 上) # 设置密码(推荐) requirepass master_password # 允许哪些 Slave 连接(默认所有) # masterauth 在 Slave 上配置

4.2 Slave 配置

# 从库配置 # 指定主库(必配) replicaof 192.168.1.100 6379 # 主库密码(如果主库设置了) masterauth master_password # 从库是否只读(默认 yes,强烈建议保持) replica-read-only yes # 主从断开后,是否继续响应读请求 # yes = 返回旧数据,no = 返回 error replica-serve-stale-data yes # 优先级(哨兵选主时,值越小越优先,0 表示永远不会被选为主) replica-priority 100

4.3 网络优化配置

# 复制超时时间(秒) repl-timeout 60 # 复制缓冲区大小(影响部分同步的成功率) repl-backlog-size 100mb # 是否使用无盘复制(直接通过网络发送 RDB,不落盘) # 适合磁盘慢但网络快的场景 repl-diskless-sync yes # 无盘复制的延迟时间(等待更多 Slave 一起同步) repl-diskless-sync-delay 5

五、 复制拓扑:三种主流架构

5.1 一主一从

Master → Slave

适用:小规模应用,备份为主
优点:简单
缺点:读压力大时 Slave 成为瓶颈

5.2 一主多从(星型)

┌─── Slave1 Master ─┼─── Slave2 └─── Slave3

适用:读多写少的场景(如排行榜、缓存)
优点:读写分离,读性能线性提升
缺点:Master 写压力不变,网络带宽占用大

5.3 级联复制(树型)

Master → Slave1 → Slave2 └──→ Slave3

适用:跨机房部署(主库写,从库级联到其他机房)
优点:减轻 Master 的网络压力
缺点:链路越长,延迟越大

配置级联

# Slave1(同时作为 Slave2 的 Master)127.0.0.1:6380>REPLICAOF192.168.1.1006379# Slave2127.0.0.1:6381>REPLICAOF192.168.1.1016380# 指向 Slave1

六、 监控与运维

6.1 查看复制状态

# 查看主库的复制状态redis-cli-p6379INFO replication# 输出示例# Role:master# connected_slaves:2# slave0:ip=127.0.0.1,port=6380,state=online,offset=12345,lag=0# slave1:ip=127.0.0.1,port=6381,state=online,offset=12345,lag=0# master_replid:3a9c1d7e...# master_repl_offset:12345
# 查看从库的复制状态redis-cli-p6380INFO replication# 输出示例# Role:slave# master_host:127.0.0.1# master_port:6379# master_link_status:up# slave_repl_offset:12345# master_last_io_seconds_ago:0

关键指标

  • master_link_status:up(正常)/ down(断开)
  • lag:从库延迟的秒数(理想是 0)
  • slave_repl_offset:从库的复制偏移量

6.2 手动触发同步

# 在从库上强制全量同步redis-cli-p6380SLAVEOF NO ONE# 断开redis-cli-p6380SLAVEOF127.0.0.16379# 重连(会触发全量)

6.3 常见问题排查

问题 1:Slave 延迟过高(lag > 5)

原因:

  • Slave 机器性能差(CPU/内存/网络)
  • Master 写 QPS 太高,Slave 执行跟不上
  • 网络带宽不足

解决:

  • 升级 Slave 配置
  • 增加级联复制,分担压力
  • 调整repl-backlog-size

问题 2:主从断开后重连触发全量同步

原因:

  • Slave offset 已不在 Master 的 backlog 中
  • Master 的repl-backlog-size太小

解决:

  • 增加repl-backlog-size(推荐 100MB - 1GB)
  • 检查网络是否频繁抖动

问题 3:数据不一致

原因:

  • 使用了非幂等的命令(如INCRRPUSH)在主从切换时可能重复执行

解决:

  • 使用幂等的业务逻辑
  • 更严重的不一致,用哨兵 + 半同步方案

七、 复制的一些陷阱

7.1 写操作只能在 Master

# Slave 上默认是只读的127.0.0.1:6380>SET name"Tom"(error)READONLY You can'twriteagainst areadonly replica.# 除非修改配置(不推荐)replica-read-only no

7.2 主从延迟导致数据不一致

# Master 写入Master: SET counter100# 立即在 Slave 读取(可能还没同步)Slave: GET counter# 可能还是 99

解决方案

  • 关键读操作强制读 Master(通过代码控制)
  • 使用WAIT命令(阻塞直到数据同步到 N 个 Slave)
# Master 上执行,阻塞直到至少 2 个 Slave 确认同步127.0.0.1:6379>SET counter100OK127.0.0.1:6379>WAIT21000(integer)2# 2 个 Slave 在 1000ms 内确认

7.3 主从切换时的数据丢失

如果 Master 宕机,Slave 被提升为新 Master,但旧 Master 上还有一些没同步到 Slave 的写命令,这些数据就永久丢失了。

解决方案

  • 配置min-slaves-to-writemin-slaves-max-lag(至少 N 个 Slave 在线且延迟 < M 秒,Master 才接受写)
# redis.conf(Master) # 至少有 1 个 Slave,且延迟 ≤ 10 秒,才接受写 min-slaves-to-write 1 min-slaves-max-lag 10

如果条件不满足,Master 会拒绝写请求,并返回错误。虽然降低了可用性,但保证了数据不丢。


八、 生产最佳实践

8.1 推荐配置

# Master 配置 requirepass YourStrongPassword repl-backlog-size 256mb # 足够大,避免部分同步退化 min-slaves-to-write 1 # 至少 1 个健康的 Slave min-slaves-max-lag 10
# Slave 配置 replicaof 192.168.1.100 6379 masterauth YourStrongPassword replica-read-only yes replica-serve-stale-data yes repl-timeout 60

8.2 监控告警项

指标告警阈值处理
master_link_statusdown立即排查网络/防火墙
lag> 5 秒检查 Slave 性能/网络
connected_slaves< 2(期望值)检查 Slave 是否掉线
master_repl_offset - slave_repl_offset> 1MBbacklog 可能太小

8.3 备份策略

# 在 Slave 上做备份(不占用 Master 资源)redis-cli-p6380BGSAVE# 每天定时备份 RDB 文件到远程服务器02* * *scp/var/lib/redis/dump.rdb backup@remote:/backup/redis-$(date+\%Y\%m\%d).rdb

九、 面试高频题

Q1:主从复制的原理是什么?

A:分三个阶段:

  1. Slave 发送PSYNC请求
  2. Master 执行BGSAVE生成 RDB 并发送给 Slave(全量同步)
  3. Master 把后续写命令持续发送给 Slave(增量同步)
  4. 断线重连后,如果 offset 在 backlog 中,执行部分同步;否则退化为全量同步

Q2:全量同步时,Slave 能提供服务吗?

A:

  • 如果replica-serve-stale-data = yes(默认),Slave 会返回旧数据
  • 如果 = no,Slave 返回错误

Q3:主从复制是异步还是同步?

A:默认异步。Master 写完本地就返回客户端,不等待 Slave 确认。但可以用WAIT命令实现半同步。

Q4:主从延迟怎么解决?

A:

  • 优化网络(同机房部署)
  • 提升 Slave 配置(CPU/内存)
  • 关键操作读 Master
  • 使用WAIT命令(但会降低性能)

Q5:怎么平滑地升级 Master?

A:

  1. 选一个 Slave,执行REPLICAOF NO ONE提升为 Master
  2. 把其他 Slave 指向新 Master
  3. 把旧 Master 降级为 Slave

十、 总结

主从复制是 Redis 高可用的基石,虽然它本身不能自动故障转移(那是哨兵的工作),但已经解决了 80% 的问题:

你的需求是否用主从
提高读并发✅ 一主多从
数据备份✅ 从库做备份
读写分离✅ 写主读从
自动故障转移❌ 需要哨兵(下一期)
海量数据存储❌ 需要集群(下下期)

最后的叮嘱

  • 主从不是越多越好,每个 Slave 都会增加 Master 的网络带宽压力
  • 推荐:1 主 2 从 或 1 主 3 从,再多就用级联复制
  • 生产环境务必配置密码(requirepass+masterauth
  • 定期检查复制延迟,这是很多事故的根源

下一期预告:Redis 哨兵模式——自动故障转移,让 Redis 永不宕机

复制一时爽,监控要跟上。下期见!

http://www.cnnetsun.cn/news/2785997.html

相关文章:

  • 社区养老丨2026年物业企业的新赛道机会
  • 保姆级教程:威纶通MT8071ip触摸屏与正点原子STM32F103的Modbus接线实战(附避坑清单)
  • 买路由器,到底是在买什么?
  • MusicFree插件开发终极指南:5个步骤打造你的个性化音乐播放器
  • Linux串口调试不止minicom:聊聊它的HEX显示、自动换行和那些隐藏的实用技巧
  • ZYNQ新手避坑指南:用ILA和SDK联合调试AXI总线,手把手抓取第一个波形
  • STM32温度传感器怎么选?DS18B20 vs LM335实测对比与选型指南
  • ArcGIS表格转矢量踩过的坑:从坐标格式混乱到投影错误,我的避坑实战记录
  • 别再为本地GPU发愁了!手把手教你用Google Colab免费GPU跑通GitHub上的深度学习项目
  • 从‘行频’到‘帧率’:深入理解Basler线扫相机采集速度的底层逻辑与实战调优
  • 【最新】微元算力聚合平台实战:高并发场景下的API网关优化方案
  • ARM芯片加密狗D8/YT88深度体验:除了防破解,它还能为你的Web应用做身份认证?
  • GPT-4生成可编辑数据图表的四层提示工程方法
  • 实战演练:基于快马平台生成集成spring security和jwt的springboot权限系统
  • 下载 | Win10 LTSB 2016官方精简版,适合低配老电脑的系统!(集成5月最新补丁、Win10 1607)
  • 从二极管到MOS管:手把手教你用万用表和示波器调试UART电平转换电路
  • 华东数交,期待与您共同开启数据资产的“价值觉醒“
  • ReplayBook:英雄联盟回放管理分析工具终极指南
  • C#项目集成Bartender打印与导出:从环境配置到异常处理的全流程指南
  • 从负载线到开关速度:三极管深度饱和的实战设计与权衡
  • OpenWRT Could not open mtd device: FIP
  • Vue3 编译优化
  • 09API:给开发者准备的 AI 大模型中转服务
  • 5分钟快速上手:Carrot插件终极实时Codeforces评级预测指南
  • 2026宁夏物联网开发公司实力测评:五大口碑优选品牌
  • 显卡完全指南:从「5090是什么」到大学电脑怎么选
  • 【采购申请的校验——成本中心范围】
  • 2026年达州市高新技术企业申报!申报时间、认定条件、办理流程、补贴奖励全攻略
  • 从代码到芯片:一个程序的完整底层执行之旅
  • 硬件设计干货|基于 CK6865L 的音箱彩灯二合一方案,硬件直连声光链路优化同步延时