一、持久化核心概念
1.1 什么是持久化?
定义:将内存中的数据保存到非易失性存储介质(磁盘),防止进程退出或系统崩溃造成数据丢失。
1.2 Redis持久化特点
写入路径:客户端 → 内存 → 磁盘(异步)
读取路径:内存 ← 客户端
恢复路径:磁盘 → 内存(重启时)
二、Redis持久化策略总览
2.1 两种策略对比
| 特性 | RDB(定期备份) | AOF(实时备份) |
|---|---|---|
| 原理 | 生成数据快照 | 记录写命令日志 |
| 文件格式 | 二进制 | 文本 |
| 恢复速度 | 快 | 慢 |
| 数据安全性 | 可能丢失最近数据 | 数据丢失风险低 |
| 文件大小 | 小 | 大 |
| 适用场景 | 备份、全量复制 | 高数据安全性要求 |
2.2 架构图:Redis持久化总体架构
客户端请求 Redis主线程 持久化策略 RDB机制 定期快照 bgsave子进程 二进制文件 AOF机制 实时记录 主线程/子进程 文本文件 磁盘存储 重启恢复
三、RDB机制深度解析
3.1 RDB核心概念
定义:Redis DataBase,定期生成redis的内存数据的完整快照。
工作机制:
周期触发 → 内存快照 → 二进制压缩 → 磁盘存储
3.2 触发机制分类图
RDB触发机制 手动触发 自动触发 save命令 bgsave命令 配置定时 shutdown命令 主从复制 前台阻塞 后台异步 save规则 正常关闭 全量同步
四、RDB触发机制详解
4.1 手动触发
4.1.1 save命令(❌ 生产环境禁用)
执行流程:
save命令 → 阻塞所有线程 → 同步写盘 → 返回结果
save命令,会让redis的所有线程,全部都来执行持久化的任务,生成快照文件,
由于所有的线程都来进行持久化,主线程就没有办法处理客户端的其他命令请求了,客户端也就阻塞住了 ,效率就降低了,
同时,其他的客户端就会直接去访问mysql获取数据,mysql面对突然的大流量访问,
可能导致mysql也一起崩溃了。
因此,save命令在生产环境永远不要使用。
问题分析:
- 服务阻塞:所有客户端请求被挂起
- 级联故障:可能导致依赖服务(如MySQL)压力激增
- 性能影响:大内存实例可能阻塞数秒至数分钟
4.1.2 bgsave命令(✅ 推荐使用)
执行流程图:
Client Redis主进程 RDB子进程 bgsave命令 检查是否存在RDB进程或AOF进程 fork()创建子进程 "Background saving started" 继续处理其他请求 正常处理命令 执行rdbSave() 生成临时RDB文件 文件校验 替换旧文件 发送SIGCHLD信号 par [主进程和子进程并行] "Already saving in background" alt [无正在执行的RDB/AOF] [已有RDB进程] Client Redis主进程 RDB子进程
关键特性:
- 单实例限制:同一时间只允许一个bgsave子进程
- 写时复制:利用fork()的COW机制保证数据一致性
- 信号通知:子进程完成时通过SIGCHLD通知父进程回收子进程,避免出现僵尸进程
4.2 自动触发
4.2.1 配置文件定时触发
默认配置解析:
conf
# 配置格式:save <seconds> <changes>
save 900 1 # 15分钟内至少1次修改
save 300 10 # 5分钟内至少10次修改
save 60 10000 # 1分钟内至少10000次修改
触发条件检查算法:
上次RDB保存时间 = last_save_time
当前时间 = current_time
修改计数器 = dirty_counter
if (current_time - last_save_time > 60s) {
if (dirty_counter > 10000) trigger_bgsave()
} else if (current_time - last_save_time > 300s) {
if (dirty_counter > 10) trigger_bgsave()
} else if (current_time - last_save_time > 900s) {
if (dirty_counter > 1) trigger_bgsave()
}
4.2.2 其他自动触发场景
- 正常关闭服务 :
shutdown命令执行前自动触发bgsave - 主从全量同步:主节点为从节点生成RDB文件
- 调试命令 :
debug reload等命令触发
虽然触发RDB的条件可以修改,但是,需要遵循一个原则,不能够太频繁的触发RDB操作,
毕竟RDB操作的消耗是比较大的,需要将redis内存中所有的数据全部都写入到快照文件中。
这同时也存在一定的隐患,由于不能够太频繁的触发RDB操作,
如果短时间内突然来到了大量的修改,RDB操作无法被触发,并且,此时redis服务器挂掉了(一定是异常挂掉,正常关闭会自动RDB持久化),
那这些大量修改的数据没有被持久化,就很危险,出现数据丢失了。(AOF持久化机制就能够解决该问题)
五、RDB核心技术:fork与写时复制
5.1 进程模型选择分析
为什么是创建子进程而不是创建新线程?
| 对比维度 | 子进程方案 | 线程方案 |
|---|---|---|
| 内存隔离 | 完全隔离 | 共享地址空间 |
| 数据一致性 | fork瞬间快照 | 需要额外同步 |
| 实现复杂度 | 简单可靠 | 复杂易错 |
| 性能开销 | 页表复制 | 全量数据复制 |
| 资源管理 | 独立资源 | 共享资源 |
| 安全性 | 子进程不会影响父进程 | 一个线程异常,整个进程崩溃 |
为什么使用子进程,而不是新起一个线程呢?
使用子进程是为了利用fork创建子进程的时候,写时拷贝的特性,
在创建子进程的时候,子进程会继承父进程的几乎所有东西,尤其是继承了父进程的进程地址空间,页表等,
并且父进程和子进程的数据是独立的,子进程继承的一瞬间,快照就形成了,父进程进行修改,会触发写时拷贝,父进程的修改,子进程是不可见的,就完美的生成了快照,
对此时的快照进行RDB持久化即可。
当子进程完成RDB持久化后,向父进程发送SIGCHID信号,父进程就可以等待回收子进程了,避免出现僵尸进程,内存泄漏。
反倒是创建新线程,由于线程之间共享进程地址空间,共享页表,主线程一旦修改,新线程也能看到,这样就无法保证快照是创建新线程的一瞬间的快照(有点类似于不可重复读的感觉),
要解决这个问题,需要在创建新线程的时候,将redis在内存的数据拷贝一份,
将这个拷贝后的数据作为快照,消耗太大了,效率又低,显然不如fork创建子进程划算。
并且,由于一个线程异常会整个进程崩溃,使用线程不够安全。
5.2 fork()写时复制机制详解
流程示意图:
Redis主进程 fork调用 子进程创建完成 父进程内存空间 子进程页表指向相同物理页 父进程修改数据 触发写时复制 分配新物理页给父进程 子进程继续访问旧数据页 子进程RDB持久化 写入旧数据快照
技术优势:
- 零拷贝快照:子进程获得fork时刻的内存镜像
- 无锁并发:父进程继续服务,无需暂停
- 内存高效:只在实际修改时复制数据页
- 数据一致:保证快照的时间点一致性
六、RDB文件管理
6.1 文件结构与位置
默认配置:
工作目录:/var/lib/redis/
文件名:dump.rdb
配置文件:redis.conf中dir和dbfilename参数
文件生成过程:
是 否 开始bgsave 创建临时文件
temp-.rdb 子进程写入数据 文件校验 校验通过? 删除旧dump.rdb 删除临时文件
并报错 重命名为dump.rdb RDB完成
由于恢复历史数据,只需要恢复最新的历史数据就行了,所以rdb镜像文件只需要保存一个最新的就行了。
当执行了bgsave命令的时候,会先生成一个临时的rdb镜像文件,这个新的快照文件完成之后,进行校验,没有问题,
就会把老的rdb镜像文件删除,然后将临时的rdb镜像文件改名成dump.rdb,
保证从始至终只有一份rdb镜像文件。
6.2 文件检查与维护
完整性检查工具:
bash
# 检查RDB文件是否损坏
redis-check-rdb /var/lib/redis/dump.rdb
# 检查结果示例
[OK] 12345 bytes read
[OK] 987 keys read
[OK] 0 expires
[OK] 0 already expired
文件管理策略:
- 单文件策略:始终只保留最新的dump.rdb
- 原子替换:通过临时文件+重命名保证文件完整性
- 版本兼容:不同Redis版本的RDB格式可能不兼容,需要手动处理兼容问题
七、RDB优缺点总结
7.1 优势
- 恢复速度快:二进制加载,大数据集恢复迅速
- 文件紧凑:压缩存储,节省磁盘空间
- 适合备份:单个文件方便传输和归档
- 全量复制:主从同步时效率高
- 性能影响小:bgsave期间服务基本不受影响
7.2 劣势
- 数据丢失风险:两次RDB之间的数据可能丢失
- fork开销:大数据集时fork可能阻塞主进程
- 不可控触发:自动触发时机不精确
- 版本兼容问题:不同版本格式可能不兼容
7.3 适用场景
- 数据备份:定期全量备份
- 灾难恢复:快速重建实例
- 数据迁移:跨实例数据转移
- 主从同步:全量数据复制
- 开发测试:快速数据重置
八、 总结
RDB作为Redis的定期快照 持久化机制,通过fork子进程+写时复制 实现了高效、一致 的数据备份。虽然存在数据丢失风险 ,但其恢复速度快、文件紧凑 的特点使其在备份、全量复制等场景中具有不可替代的价值。
核心要点回顾:
- 使用bgsave避免服务阻塞
- 理解fork写时复制的工作原理
- 合理配置save规则平衡性能与安全
- 定期检查RDB文件完整性
- 结合业务特点选择RDB与AOF组合策略
在下一篇文章中,我们将深入解析AOF持久化机制,探讨如何实现更高程度的数据安全性保障。