Redis持久化三剑客:RDB二进制快照、AOF文本日志、混合模式如何守护你的数据安全?

文章目录

本篇摘要

本文围绕Redis持久化展开,介绍其引入背景后,详细阐述RDB(快照式,恢复快但易丢数据)与AOP(日志式,安全性高但文件大),还涉及混合持久化及两者对比与选择。

一.Redis持久化的引入

  1. 内存数据的易失性:Redis数据存储在内存中,断电或重启后数据会丢失,持久化是为了将内存数据保存到磁盘,以便恢复。
  2. 持久化的意义:保证数据安全性,防止数据丢失;支持数据恢复,应对故障或灾难。

二.RDB(Redis Database)持久化

  1. 定义与原理:
  • RDB是Redis默认的持久化方式(定期备份),通过快照(snapshot)的形式将某一时刻的内存数据完整地保存到磁盘上的一个二进制文件(默认dump.rdb)中。

这里默认可以看到,都是对应的保存的二进制文件(节省空间)。

这里是采取替代方式进行更新(如子进程先进行搞一个tmp文件进行存储,然后完成后,删除原dump文件,再重命名下)

服务端重启后,进行加载,一旦有问题就会报错(如网络传输),因此可以加载前检查一下:

可以配合整个程序,用指令进行检查。

  • 触发方式包括手动触发(save、bgsave命令)和自动触发(配置save规则,如save 900 1表示900秒内至少有1个key变化则触发)。
  1. save与bgsave区别:

1.save(一般不建议用,一般是直接同一文件写入不进行替换,有些ext4文件系统就会进行替换inode):

  • 在主线程执行,会阻塞Redis服务,期间无法处理其他请求,适用于数据量小或对实时性要求高的场景。

  • save 配置:通过 "save m n" 配置,若 m 秒内数据集有 n 次修改,自动触发 RDB 持久化。

  • 主从全量复制:从节点执行全量复制时,主节点自动 RDB 持久化,并将 RDB 文件发给从节点。

  • 关闭 Redis:执行 shutdown 命令关闭 Redis 时,自动执行 RDB 持久化。

位置及更改规则如下:

下面更改进行实操下:

  • 改完一定要重启,才能生效。
  • 此时save生效了,对应文件不是同一文件变化,而是重新生成文件进行同步磁盘。

2·bgsave(background save):

  • fork一个子进程来执行快照操作,主线程可继续处理请求,阻塞时间短,是常用的触发方式。

大致过程:

  • 检查子进程 :执行 bgsave 时,Redis 父进程先检查是否有其他子进程(如 RDB/AOF 子进程)在执行,若有则直接返回。
  • Fork 子进程 :父进程通过 fork 创建子进程,fork 期间父进程会阻塞;可通过 info stats 查看 latest_fork_usec 了解最近一次 fork 耗时(微秒)。
  • 返回与继续响应 :fork 完成后,bgsave 返回 "Background saving started",父进程不再阻塞,可继续处理其他命令。
  • 生成 RDB 文件 :子进程基于父进程内存生成临时快照并原子替换旧文件;用 lastsave 可查看最后一次生成 RDB 的时间,对应 info 里的 rdb_last_save_time。
  • 完成通知与统计更新:子进程完成后发信号给父进程,父进程更新相关统计信息。

下面来操作下:

redis默认生成的文件都是在里面:

下面插入几个值测试下:

  • 发现没有变化(这里前提是不能退出客户端,如果退出了,默认就会更新一次)。

因为有一定规则约束,所以不能及时更新:

  • 这两个条件必须同时满足,才会更新(比如 900秒内操作至少一次更改,900秒后就会更新rdb文件)。

带来的缺点:

对应的磁盘库内与内存不同步,如果服务器突然崩掉,就会造成数据损失,因此考虑手动同步(bgsave):

  • 发现已经同步了,这里如果数据小,会很快,否则要等待一会。

下面重启下redis服务端看是否恢复:

  • 发现确实从磁盘同步回来了。

对于自动触发还有几种:

一是配置文件中按"save M 时间内修改 N 次"规则触发;二是使用shutdown命令正常关闭redis服务器时触发;三是redis主从复制时,主节点自动生成rdb快照并传输给从节点。

但是对应异常退出,就不会保存了(服务器都没反应过来就完了):

异常重启(如 kill -9 或服务器掉电),Redis 来不及生成 RDB,内存中未保存到快照的数据会随重启丢失。

如下:

  • 这里插进去了对应的key为9的情况,但是服务端异常挂掉,会由守护进程找一个新进程替代,但是发现之前的进程没来得及保存数据就挂了。

那么如何知道rdb文件是被替换了文件而不是文件重写呢?

可以看每个文件独有的indode编号:

  • 发现确实变了。

简单认识下inode:

  • Linux文件系统中,ext4典型组织方式将文件系统分为三大部分。

  • 超级块:存放管理信息。

  • inode区:存放inode节点,每个文件对应一个inode数据结构,含文件元数据(属性)。

  • block区:存放文件的数据内容。

下面测试下如果把对应的rdb文件搞坏会咋样?

首先对rdb文件进行末尾修改:

不能直接温和手段让它恢复(比如restart)这样它会重新从内存进行同步,来新搞一个rdb文件,因此这里选择kill来粗暴解决:

  • 发现正常启动,因此服务端重启的时候把上面内容成功读取后就不管后面了。

下面试着改变中间部分,再次杀死服务端进程进行重启:

新的rdb文件空了:

  • 结果无论如何也启动不了服务端了。

下面查看下日志:

  • 发现重启时候加载rdb文件出错了。

因此可以通过之前说的检测rdb文件工具进行提前检查:

  • 检查出问题了。

那怎么正常启动呢?

很简单,把对应的rdb文件删除,进行重启服务(此时服务端就会加载发现没这个文件,就当做本身rdb文件就没内容,直接启动不进行加载了,不过redis客户端内容就都没了。)

  • 发现出错状态客户端是进不去的。

下面进行操作:

  • redis两端运行正常了。

3. RDB文件结构:

  • 包含Redis版本、数据库数量、每个数据库的key-value对等信息,以二进制格式存储,便于快速恢复。
  1. 优点:
  • 恢复速度快:二进制文件加载比AOF的命令重放更快(直接把二进制按照字节读到内存,而AOF是文本存储,需要字符串进行切割,故慢)。
  • 文件体积小:只保存某一时刻的完整数据,压缩后体积更小。
  1. 缺点:
  • 数据丢失风险:两次快照之间的数据变化会丢失(取决于save规则)。
  • fork子进程可能造成短暂阻塞:数据量大时,fork过程会消耗较多资源和时间。
  • Redis版本演进过程中有多个RDB版本,兼容性可能有⻛险(写一个程序把旧的key内容依次拷贝到新的redis服务器中去)。

三.AOF(Append Only File)持久化

  1. 定义与原理:
  • AOF(实时备份)以日志的形式记录Redis服务器执行的写操作命令(如set、del等),在服务器重启时,通过重新执行这些命令来恢复数据(类似于mysql的binlog,一旦开启后rdb不在生效,默认关闭需要手动打开)。

  • AOF通过顺序写入指令与独特的缓冲区刷新策略,使得整体性能还是不错的。

  • 命令写入策略:有always(每次写操作都同步到磁盘)、everysec(每秒同步一次)、no(由操作系统决定何时同步)三种,权衡数据安全性和性能(默认是everysec模式(性能与防止意外发生做到了折中的权衡))。

更改策略入下(配置文件):

记得重启服务端。

因此对应AOF模式工作流程:

演示下操作:

进行启动AOF模式:

  • 重启下服务端,发现生成了对应aof文件。

下面进行插入:

杀死服务端,自动重启完服务端:

  • 登录客户端发现数据还在。
  • 对应的之前的操作指令都被保存了(服务端重启的时候就会依次解析出来执行对应命令,还原内存中)。
  1. AOF重写(AOF Rewrite):
  • 目的:解决AOF文件不断增大导致恢复变慢的问题(如:剔除冗余操作、合并部分操作)。

  • 原理:fork一个子进程,基于当前内存数据生成一份精简的AOF文件(只包含最终状态的命令),然后用新文件替换旧文件。

如图:

下面解释下:

1. 通过fork创建子进程,父进程负责接收客户端请求,子进程负责对AOF文件进行重写。

2. 子进程读取内存中原先父进程的那块缓冲区内容按照RDB快照即文本格式进行通过缓冲区模式写入到对应的新的AOF文件中(如果出现冗余操作会自动合并)。

3. 父进程此时还可以继续接受请求进行redis任务操作(但是是发生的写时拷贝,不影响子进程重写之前父进程的内容),之后父进程得到的新数据指令一份写在aof_rewrite_buf缓冲区(进而写入新aof文件),一份写在原先的aof_buf缓冲区中(写入旧文件以防备意外导致崩了导致内存数据丢失,aof_buf缓冲区继续同步旧aof文件,起到备份作用)。

4. 等到子进程完成完原先内存中数据重写后,通知父进程,然后父进程进行aof_rewrite_buf`缓冲区数据更新到新aof文件,然后通过重新命名覆盖方式替换掉原先即aof文件(此过程有新数据来也几乎不会舍去)。

  • 触发方式:手动触发(bgrewriteaof命令)和自动触发(配置auto - aof - rewrite - percentage和auto - aof - rewrite - min - size,如当AOF文件大小增长到上次重写后的100%且超过64MB时触发)。
  1. 优点:
  • 数据安全性高:everysec策略下最多丢失1秒内的数据;always策略几乎不丢失数据。
  • 可读性强:以文本日志形式记录命令,便于排查问题。
  1. 缺点:
  • 文件体积大:随着时间推移,AOF文件会不断增大,恢复速度比RDB慢。
  • 恢复速度慢:需要重放所有写操作命令,数据量大时恢复时间长。

基于bgsave过程可能出现问题:

  • 执行bgsave时,若redis正在执行aof重写,当前这次bgsave不会执行,立马返回正在重写的话语。
  • 执行bgrewriteaof时,若redis正在dump rdb文件,aof重写会等待rdb快照生成完毕后再执行。
  • 重写过程如果意外,导致内存数据丢失(如服务器挂了),此时父进程对应的原先的旧的aof文件中仍记录了重写过程中接收到新的指令的数据,因此可以应对这种情况发生(相当于原文件不变,重启还是从这个旧的aof文件同步数据)。

四.Redis混合持久化

  1. AOF基本原理
  • AOF按文本写入文件,随机访问成本高,redis引入混合持久化结合rdb和aof特点(需要手动启动,见下面测试)。
  • 按aof方式每个写命令写入文件(文本),恢复aof文件后,将当前持久化方式按rdb二进制格式写入aof文件(重写的时候父子缓冲区进来的都是二进制形式,然后再换名式覆盖旧aof文件),后续操作仍按aof文本追加。
  1. AOF与RDB持久化选择
  • redis同时存在aof文件和rdb快照时,默认自动以aof为主,rdb被忽略(但是如果rdb手动同步,还是会响应的),说明AOF保存数据比RDB全。

3.基于Redis混合持久化的测试:

打开对应的混合持久化模式:

重启服务端:

  • 可以发现现在全是文本格式。

下面进行aof手动同步,看下对应文件变化,然后在进行插入看下变化:

  • 重写后变成二进制格式,符合预期。
  • 重写的时候采取的是二进制格式(rdb模式),但是后期进行aof格式同步指令数据到aof文件就是文本格式,符合混合持久化预期。

五.RDB与AOF对比与选择

  1. 对比维度:
  • 数据安全性:AOF > RDB(AOF可通过策略减少丢失,RDB存在时间窗口丢失风险),一个实时同步,一个定期同步。
  • 恢复速度:RDB > AOF(RDB二进制加载快,AOF需重放命令)。
  • 文件体积:RDB < AOF(RDB只存快照,AOF存命令日志)。
  • 性能影响:RDB的bgsave相对AOF的everysec对性能影响较小(AOF需持续写入日志)。
  1. 选择建议:
  • 对数据安全性要求极高,可接受一定恢复时间:优先AOF,甚至结合always策略和AOF重写。
  • 对恢复速度要求高,能容忍部分数据丢失:优先RDB,或结合RDB与AOF(Redis 4.0+支持混合持久化)。
  • 混合持久化(Redis 4.0+):结合RDB和AOF的优点,先通过RDB生成快照,再将RDB之后的写操作以AOF日志形式记录,恢复时先加载RDB再重放AOF日志,兼顾速度与安全性。

六.基于持久化小结

  1. Redis提供RDB和AOF两种持久化方案。
  2. RDB是内存快照,内容紧凑、占用空间小、恢复快,但生成开销大,不适合实时持久化,常用于冷备和主从复制。
  3. AOF保存修改命令,恢复时重放命令,有重写机制压缩文件。
  4. RDB和AOF都可以通过fork创建子进程,利用Linux子进程内存快照特点进行持久化,尽量不影响主进程处理后续命令。

七. 本篇小结

介绍Redis通过RDB和AOF实现数据持久化,RDB适合冷备等场景,AOF保障数据安全,混合持久化结合二者优势,实际应用需依需求选方案。

相关推荐
小呆爱发呆19 分钟前
第三章 MySQL 库表操作
数据库·mysql·adb
时间的拾荒人1 小时前
Redis 进阶实战:渐进式遍历、持久化机制与事务详解
数据库·redis·缓存
普通人62 小时前
MySQL_FIND_IN_SET函数详解
android·数据库·mysql
真上帝的左手2 小时前
4. 关系型数据库-MySQL-Canal 进阶
数据库·mysql·canal
xiaoye-duck2 小时前
《C++ 项目:手写大模型接入 SDK》DataManager数据管理模块:SQLite持久化存储
开发语言·数据库·c++·sqlite
唐老板3 小时前
uuidv7 来了:为什么别再拿 uuidv4 当主键了
数据库
SelectDB16 小时前
让变更流出 Doris:Apache Doris 5.0 基于增量计算的 CDC 技术解析
数据库