【Redis】主从复制Day9
写在前面
在实际生产环境中,单机Redis面临两个核心问题:性能瓶颈和单点故障。主从复制是Redis实现高可用的基础,它不仅解决了数据冗余备份问题,还为读写分离、故障转移提供了可能。今天我们深入理解Redis主从复制的原理与实践。
文章目录
- 写在前面
- 一、为什么需要主从复制?
- 1.1 单机Redis的局限性
- 1.2 主从复制的价值
- 二、主从复制原理
- 2.1 复制流程概述
- 2.2 全量同步(SYNC)
- 2.3 部分同步(PSYNC)
- 2.4 命令传播
- 三、主从复制配置
- 3.1 配置方式
- 3.2 重要配置参数
- 3.3 查看复制状态
- 四、主从切换
- 4.1 手动主从切换
- 4.2 读写分离配置
- 五、踩坑提醒
- 六、主从复制优化
- 6.1 配置优化
- 6.2 架构优化
- 七、面试高频考点
- 考点1:主从复制的流程?
- 考点2:如何减少主从复制延迟?
- 考点3:主从复制是同步还是异步?
- 考点4:SYNC和PSYNC的区别?
- 八、参考资料
- 九、互动话题
一、为什么需要主从复制?
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 命令传播
同步完成后,主节点持续将写命令发送给从节点:
# 主节点执行写命令 SET key1 value1 # 主节点将命令传播给从节点 # 从节点执行相同的命令保持数据一致三、主从复制配置
3.1 配置方式
方式一:配置文件
# redis.conf(从节点配置) replicaof 192.168.1.100 6379 # Redis 5.0之前使用 # slaveof 192.168.1.100 6379 # 从节点只读 replica-read-only yes # 主节点密码 masterauth "your_password"方式二:命令行
# 在从节点执行 REPLICAOF 192.168.1.100 6379 # 取消主从关系 REPLICAOF NO ONE3.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 查看复制状态
# 查看主从复制信息 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 手动主从切换
踩坑提醒:手动切换需要谨慎操作,确保数据同步完成后再切换,否则可能丢失数据。
步骤:
# 1. 在新主节点执行,停止复制 REPLICAOF NO ONE # 2. 在其他从节点执行,指向新主节点 REPLICAOF new_master_ip 6379 # 3. 验证主从状态 INFO replication4.2 读写分离配置
应用层需要区分读写请求:
# 主节点地址(写操作)MASTER_HOST=192.168.1.100MASTER_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 |
| 增加带宽 | 提高复制带宽限制 |
# 调整复制带宽限制 repl-backlog-size 64mb # 增大复制缓冲区 client-output-buffer-limit replica 256mb 64mb 60踩坑提醒:主从切换数据丢失
问题描述:
异步复制场景下,主节点宕机时,从节点可能还没收到最新的写命令。
解决方案:
- 配置合理的
min-replicas-to-write - 使用哨兵或集群实现自动故障转移
- 业务层实现重试机制
# 至少有1个从节点才能写入 min-replicas-to-write 1 min-replicas-max-lag 10踩坑提醒:全量同步阻塞
问题描述:
主节点执行BGSAVE生成RDB时,如果内存数据量大,会消耗大量CPU和内存,影响性能。
解决方案:
- 使用无盘复制
- 控制单实例内存大小
- 在低峰期添加从节点
# 开启无盘复制 repl-diskless-sync yes repl-diskless-sync-delay 5六、主从复制优化
6.1 配置优化
# 增大复制缓冲区 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 606.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之后 |
| 同步方式 | 只支持全量同步 | 支持全量和部分同步 |
| 断线重连 | 需要全量同步 | 可能只需部分同步 |
| 性能 | 低 | 高 |
| 资源消耗 | 高 | 低 |
八、参考资料
Redis官方文档 - Replication
九、互动话题
- 你的生产环境主从架构是如何设计的?遇到过什么问题?
- 如何监控主从复制延迟?延迟超过多少需要告警?
- 主节点宕机后,如何实现自动故障转移?
欢迎在评论区分享你的经验和见解!
下一期预告:Day10 - Redis哨兵机制,敬请期待!
