无盘复制
00:00
Redis无盘复制:避免磁盘I/O的复制方案、配置与适用场景
1. 无盘复制概述
无盘复制(Diskless Replication)是 Redis 2.8.18 引入的特性,允许在主从复制过程中跳过磁盘 I/O,直接通过网络将 RDB 数据从主节点发送到从节点,无需在主节点磁盘上生成临时 RDB 文件。
传统复制流程:
主节点内存 → RDB文件(磁盘) → 读取磁盘 → 网络发送 → 从节点
无盘复制流程:
主节点内存 → 网络直接发送 → 从节点
2. 传统复制的磁盘瓶颈
2.1 问题分析
传统主从复制的 RDB 生成过程涉及两次磁盘 I/O:
- 写入磁盘:子进程将 RDB 数据写入临时文件
- 读取磁盘:主进程读取临时文件发送给从节点
当数据集较大时,磁盘 I/O 成为瓶颈:
2.2 磁盘瓶颈场景
| 场景 | 磁盘类型 | 数据集大小 | 磁盘写入耗时 | 网络传输耗时 |
|---|---|---|---|---|
| HDD + 大数据集 | HDD | 50 GB | ~500s | ~400s (1Gbps) |
| SSD + 大数据集 | SSD | 50 GB | ~50s | ~400s (1Gbps) |
| SSD + 小数据集 | SSD | 5 GB | ~5s | ~40s (1Gbps) |
对于 HDD 环境,磁盘 I/O 可能成为复制的主要瓶颈。
2.3 临时文件对磁盘的影响
- 临时 RDB 文件可能占用大量磁盘空间
- 频繁的全量同步会加速磁盘磨损(SSD)
- 磁盘空间不足会导致复制失败
3. 无盘复制工作原理
3.1 核心机制
无盘复制通过管道(pipe)将 RDB 数据直接从子进程传输到网络套接字:
主节点:
fork() → 子进程
│
│ 生成 RDB 数据
│
▼
管道(pipe)
│
▼
主进程读取管道 → 网络发送 → 从节点
3.2 详细流程
- 主节点收到从节点的
PSYNC请求 - 主节点判断使用无盘复制
- 主节点
fork()子进程 - 子进程将 RDB 数据写入管道(而非磁盘文件)
- 主进程从管道读取数据,通过套接字发送给从节点
- 从节点接收 RDB 数据,写入临时文件
- 从节点加载临时 RDB 文件完成同步
3.3 管道缓冲区
管道有容量限制,当子进程写入速度超过网络发送速度时,管道缓冲区满,子进程被阻塞:
// 管道缓冲区大小
#define PIPE_BUF 65536 // 64KB (Linux 默认)
// 实际 Redis 使用更大的管道
// 通过 fcntl(fd, F_SETPIPE_SZ, size) 调整
Redis 会根据网络带宽动态调整管道大小,避免子进程频繁阻塞。
4. 配置与启用
4.1 核心配置
# 开启无盘复制
repl-diskless-sync yes
# 无盘复制延迟启动时间(秒)
repl-diskless-sync-delay 5
# 无盘复制加载模式(Redis 7.0+)
repl-diskless-load on-empty-db
4.2 repl-diskless-sync-delay
延迟启动是为了等待更多从节点同时连接,实现并行复制:
从节点1 连接 ──→ 等待 delay 秒
从节点2 连接 ──→ 等待 delay 秒
从节点3 连接 ──→ 等待 delay 秒
│
▼ delay 到期
一次性向所有从节点发送 RDB
- 设为
0:第一个从节点请求时立即开始复制 - 设为
5(默认):等待 5 秒,收集更多从节点 - 设为较大值:适合大量从节点同时同步的场景
4.3 repl-diskless-load
Redis 7.0+ 支持从节点无盘加载,直接从网络套接字解析 RDB 数据到内存:
# 配置选项
repl-diskless-load disabled # 禁用(默认,先写磁盘再加载)
repl-diskless-load on-empty-db # 仅当从节点数据库为空时使用
repl-diskless-load swapdb # 使用交换数据库(保留旧数据直到加载完成)
repl-diskless-load flush-before-load # 直接清空后加载(不推荐)
swapdb 模式:
1. 从节点创建备份数据库(swapdb)
2. 直接从网络加载 RDB 到主数据库
3. 加载成功后,删除备份数据库
4. 加载失败时,从备份数据库恢复
5. 无盘复制的适用场景
5.1 适合无盘复制
| 场景 | 原因 |
|---|---|
| HDD 磁盘 | 磁盘 I/O 是瓶颈,无盘复制大幅提升速度 |
| 临时磁盘 | 避免写入临时文件 |
| 高频全量同步 | 减少磁盘磨损 |
| 磁盘空间有限 | 不需要额外空间存储 RDB 文件 |
| 多从节点同时同步 | 并行发送效率更高 |
5.2 不适合无盘复制
| 场景 | 原因 |
|---|---|
| SSD 磁盘 | 磁盘 I/O 不是瓶颈 |
| 网络带宽受限 | 网络成为瓶颈,无盘复制无优势 |
| 单从节点 | 无并行复制收益 |
| 需要持久化 RDB | 无盘复制不生成磁盘文件 |
5.3 决策流程
磁盘类型?
│
├─ HDD → 网络带宽 > 磁盘写入速度? → 是 → 开启无盘复制
│ → 否 → 不开启
│
└─ SSD → 从节点数量 > 3? → 是 → 考虑开启
→ 否 → 不开启
6. 性能对比
6.1 复制耗时对比
假设数据集 20GB,HDD 写入速度 100MB/s,网络带宽 1Gbps:
| 方案 | 磁盘写入 | 磁盘读取 | 网络传输 | 总耗时 |
|---|---|---|---|---|
| 传统复制 | 200s | 200s | 160s | ~560s |
| 无盘复制 | 0s | 0s | 160s | ~160s |
| 提升比例 | - | - | - | 3.5x |
6.2 内存开销
无盘复制在复制期间的内存开销:
与传统复制相比,无盘复制的内存开销基本相同,因为两者都需要 fork() 和 COW 机制。
7. 无盘复制的注意事项
7.1 网络中断
- 无盘复制过程中网络中断,无法断点续传
- 必须重新发起全量同步
- 传统复制可以从已写入的 RDB 文件继续
7.2 多从节点同步
- 无盘复制支持同时向多个从节点发送 RDB
- 但如果从节点在不同时间请求,后到的从节点需要等待下一次全量同步
repl-diskless-sync-delay可以缓解此问题
7.3 与 AOF 的交互
- 无盘复制不影响 AOF 持久化
- AOF 仍然正常写入磁盘
- 无盘复制仅跳过复制过程中的 RDB 磁盘写入
7.4 监控指标
# 查看复制状态
INFO Replication
# 关键指标
# repl_diskless_sync: 是否开启无盘复制
# repl_diskless_sync_delay: 延迟时间
# connected_slaves: 已连接从节点数