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 三大阶段主从复制分为三个阶段建立连接 → 全量同步 → 增量同步建立连接Slave → Master: PSYNC ? -1Master → Slave: FULLRESYNC全量同步第一次或 offset 太落后Master: BGSAVE 生成 RDBMaster → Slave: 发送 RDB 文件Slave: 清空旧数据加载 RDB增量同步正常运行中Master: 将写命令写入 replication bufferMaster → Slave: 持续发送写命令Slave: 执行写命令保持同步2.2 全量同步Full Synchronization触发条件Slave 第一次连接 MasterSlave 的复制 offset 落后太多Master 的 backlog 已覆盖不到执行了SLAVEOF NO ONE后重新配置详细流程# Step 1: Slave 发送 PSYNC 命令Slave: PSYNC ?-1# Step 2: Master 返回 FULLRESYNCMaster: FULLRESYNCmaster_replidoffset# 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 SynchronizationRedis 2.8 引入了部分同步解决了网络闪断后必须全量同步的低效问题。核心机制Master 维护一个replication backlog环形缓冲区默认 1MB所有写命令同时写入 backlogSlave 断线重连后发送PSYNC runid offsetMaster 检查 offset 是否还在 backlog 中✅ 如果在发送CONTINUE然后发送 backlog 中的增量命令❌ 如果不在退化为全量同步┌─────────────────────────────────────┐ │ Master Replication Backlog │ │ 环形缓冲区默认 1MB │ ├─────────────────────────────────────┤ │ [cmd1][cmd2][cmd3]...[cmdN] │ │ ↑ ↑ │ │ Slave offset Master offset │ └─────────────────────────────────────┘配置建议# redis.conf # 增大 backlog避免网络抖动导致全量同步 repl-backlog-size 100mb # 在没有 Slave 的情况下多久释放 backlog0 永不释放 repl-backlog-ttl 3600三、 环境搭建从零开始配置主从3.1 快速搭建3 台机器或者 1 台机器 3 个端口方案一3 台物理机Master192.168.1.100:6379Slave1192.168.1.101:6379Slave2192.168.1.102:6379方案二单机 3 个实例演示用# 1. 创建三个配置文件cpredis.conf redis-6379.confcpredis.conf redis-6380.confcpredis.conf redis-6381.conf# redis-6379.confMaster port 6379 daemonize yes pidfile /var/run/redis-6379.pid logfile /var/log/redis-6379.log dir /var/lib/redis-6379 # redis-6380.confSlave 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.confSlave 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 replication3.2 动态配置不停机添加从库# 在 Slave 上执行redis-cli-p6380127.0.0.1:6380REPLICAOF127.0.0.16379OK# 取消复制Slave 变 Master127.0.0.1:6380REPLICAOF NO ONE OK3.3 验证主从同步# 在 Master 上写数据redis-cli-p6379SET nameRedis MasterOK# 在 Slave 上读取redis-cli-p6380GET nameRedis Master# 在 Slave 上尝试写应该失败redis-cli-p6380SET age18(error)READONLY You cantwriteagainst 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 1004.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 的 Master127.0.0.1:6380REPLICAOF192.168.1.1006379# Slave2127.0.0.1:6381REPLICAOF192.168.1.1016380# 指向 Slave1六、 监控与运维6.1 查看复制状态# 查看主库的复制状态redis-cli-p6379INFO replication# 输出示例# Role:master# connected_slaves:2# slave0:ip127.0.0.1,port6380,stateonline,offset12345,lag0# slave1:ip127.0.0.1,port6381,stateonline,offset12345,lag0# 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_statusup正常/ down断开lag从库延迟的秒数理想是 0slave_repl_offset从库的复制偏移量6.2 手动触发同步# 在从库上强制全量同步redis-cli-p6380SLAVEOF NO ONE# 断开redis-cli-p6380SLAVEOF127.0.0.16379# 重连会触发全量6.3 常见问题排查问题 1Slave 延迟过高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数据不一致原因使用了非幂等的命令如INCR、RPUSH在主从切换时可能重复执行解决使用幂等的业务逻辑更严重的不一致用哨兵 半同步方案七、 复制的一些陷阱7.1 写操作只能在 Master# Slave 上默认是只读的127.0.0.1:6380SET nameTom(error)READONLY You cantwriteagainst areadonly replica.# 除非修改配置不推荐replica-read-only no7.2 主从延迟导致数据不一致# Master 写入Master: SET counter100# 立即在 Slave 读取可能还没同步Slave: GET counter# 可能还是 99解决方案关键读操作强制读 Master通过代码控制使用WAIT命令阻塞直到数据同步到 N 个 Slave# Master 上执行阻塞直到至少 2 个 Slave 确认同步127.0.0.1:6379SET counter100OK127.0.0.1:6379WAIT21000(integer)2# 2 个 Slave 在 1000ms 内确认7.3 主从切换时的数据丢失如果 Master 宕机Slave 被提升为新 Master但旧 Master 上还有一些没同步到 Slave 的写命令这些数据就永久丢失了。解决方案配置min-slaves-to-write和min-slaves-max-lag至少 N 个 Slave 在线且延迟 M 秒Master 才接受写# redis.confMaster # 至少有 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 608.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 backupremote:/backup/redis-$(date\%Y\%m\%d).rdb九、 面试高频题Q1主从复制的原理是什么A分三个阶段Slave 发送PSYNC请求Master 执行BGSAVE生成 RDB 并发送给 Slave全量同步Master 把后续写命令持续发送给 Slave增量同步断线重连后如果 offset 在 backlog 中执行部分同步否则退化为全量同步Q2全量同步时Slave 能提供服务吗A如果replica-serve-stale-data yes默认Slave 会返回旧数据如果 noSlave 返回错误Q3主从复制是异步还是同步A默认异步。Master 写完本地就返回客户端不等待 Slave 确认。但可以用WAIT命令实现半同步。Q4主从延迟怎么解决A优化网络同机房部署提升 Slave 配置CPU/内存关键操作读 Master使用WAIT命令但会降低性能Q5怎么平滑地升级 MasterA选一个 Slave执行REPLICAOF NO ONE提升为 Master把其他 Slave 指向新 Master把旧 Master 降级为 Slave十、 总结主从复制是 Redis 高可用的基石虽然它本身不能自动故障转移那是哨兵的工作但已经解决了 80% 的问题你的需求是否用主从提高读并发✅ 一主多从数据备份✅ 从库做备份读写分离✅ 写主读从自动故障转移❌ 需要哨兵下一期海量数据存储❌ 需要集群下下期最后的叮嘱主从不是越多越好每个 Slave 都会增加 Master 的网络带宽压力推荐1 主 2 从 或 1 主 3 从再多就用级联复制生产环境务必配置密码requirepassmasterauth定期检查复制延迟这是很多事故的根源下一期预告Redis 哨兵模式——自动故障转移让 Redis 永不宕机。复制一时爽监控要跟上。下期见