大家好,我是小康,今天给大家聊下 redis 的几种持久化机制。
redis 持久化
前言:
在数字时代,数据的价值越来越被人们所重视。但数据只有在经过妥善保管和管理时,才能真正发挥其潜在价值。对于使用 redis 这一热门的内存数据库的开发者和企业来说,数据的持久化无疑是一个必须面对的重要议题。
我们都知道,redis 以其卓越的性能和灵活的数据结构而著称,但如何确保内存中的数据不因突发事件而丢失?如何在确保性能的前提下,为数据提供一个更加稳固的避风港?
本文将为你揭开 redis 持久化的神秘面纱,探讨其背后的机制,并帮助你为你的应用选择合适的持久化策略。
redis与内存数据库的特性
为什么redis是内存数据库?
redis是一种键值存储系统,其数据主要存储在内存中,因此被称为内存数据库。与传统的磁盘存储数据库不同,redis的设计初衷是为了提供高速、低延迟的数据访问。由于数据直接存储在内存中,可以避免磁盘i/o的开销,从而实现极高的读写速度。
🔍例子: 想象一下你在家里找一本书。如果这本书就放在你的桌子上(相当于内存),你可以立刻拿到它。但如果它放在地下室的一个盒子里(相当于磁盘),那你可能需要花费更多时间去找。redis的工作方式就像那本放在桌子上的书。
内存数据库的优点和缺点
优点:
- 速度:内存数据库如redis能够提供快速的读写能力,因为内存的访问速度远超过磁盘。
- 低延迟:数据存取的响应时间短,适合需要快速响应的应用。
- 灵活性:由于数据结构存储在内存中,redis等内存数据库支持丰富的数据类型和操作。
- 简化的数据模型:键值存储方式简化了数据模型,便于开发和维护。
缺点:
- 成本:内存通常比磁盘更昂贵,大量的数据存储需要大量的内存,可能导致高成本。
- 数据持久性风险:如果没有合适的持久化策略,突然的系统崩溃可能导致数据丢失。
- 数据容量限制:由于依赖内存,数据的容量受到物理内存大小的限制。
什么是持久化
持久化的定义:
持久化,顾名思义,指的是将短暂的、易失的数据转化为长时间保存,且不易丢失的格式。在数据库的语境中,持久化常常指的是将内存中的数据保存到硬盘或其他长期存储介质中,从而确保即使在系统崩溃、断电或其他突发事件中,数据也不会丢失。
持久化的必要性:
数据安全性:技术世界并非总是完美的。系统可能会遭受故障、崩溃或遭受攻击。在没有持久化的情况下,所有存储在内存中的数据在这些情况下都可能丢失。持久化提供了一种机制,确保这些数据在发生故障后可以被恢复。
🔍例子: 想象一下你在电脑上工作了好几个小时,突然停电了。如果你没有定期保存你的工作,那么你可能会失去所有的努力。数据库持久化就像定期保存你的文件,确保即使发生意外,你的数据也不会丢失。
redis 持久化的方式
redis 提供三种持久化的方式: 分别是 rdb(redis database snapshot) 和 aof(append only file)以及 混合持久化。
rdb
rdb是什么?
rdb 持久化方式是 redis 将当前内存中的数据快照(snapshot)保存到硬盘的过程。换句话说,redis 会创建一个代表某一时刻的数据集的磁盘文件。
例子: 想象一下相机的快门点击。每当你点击快门,你都会捕捉到那个特定时刻的场景。rdb的工作方式很相似,只不过它捕捉的是数据的状态。
理解 rdb 的本质后,你可能会问,我们如何生成这个快照呢?使用 save 和 bgsave 命令即可。
rdb 生成图解

rdb 工作原理
rdb 生成的流程图

步骤说明:
1.触发rdb生成:
触发 rdb 文件的生成有以下两种方式:
手动触发:通过执行 save 或 bgsave 命令。
自动触发:基于 redis 配置文件中的 save 指令设置的条件。(默认是通过 bgsave 命令来触发的)
redis 配置文件 save 指令设置: save 3600 1 # 3600秒内如果超过1个key被修改则生成 rdb save 300 100 # 300秒内如果超过100个key被修改则生成 rdb save 60 10000 # 60秒内如果超过10000个key被修改则生成 rdb
2.创建子进程:
当执行 bgsave 命令时,redis 主进程(父进程)会执行 fork 操作来创建一个子进程。这是一个昂贵的操作,尤其当数据集很大时。但好处是,一旦 fork 完成,父进程可以立即返回处理其他客户端请求,而不需要等待 rdb 的生成过程。
这里涉及到操作系统级别的知识。当 fork 操作执行后,子进程会获得父进程内存中的数据副本。但由于操作系统使用写时复制(copy-on-write, cow)技术,任何在父进程(redis主进程)上发生的写操作不会影响子进程中的数据。这确保了子进程中的数据是隔离的,不受父进程中数据更改的影响。
3.子进程生成rdb文件:
子进程将开始遍历整个数据集,将所有的数据写入一个新的临时rdb文件。这是一个纯i/o操作,并且是线性的,所以非常快。子进程不需要处理任何客户端请求,只专注于写 rdb 文件,所以效率很高。
注意 :线性指的是数据在磁盘上是连续写入的。
4.rdb文件替换:
一旦子进程完成了新的 rdb 文件的写入,它会替换掉旧的 rdb 文件,并发送一个信号通知父进程任务完成。然后子进程退出。
rdb 的载入
当 redis 重新启动时,如果配置为使用 rdb 持久化,它会查找 rdb 文件,并加载它。由于 rdb 文件是一个紧凑的二进制表示形式,数据加载非常快。
rdb 配置详解
redis 默认是不会开启持久化选项的,只要重启 redis,redis 之前保存的数据都会丢失的。因此在实际的生产环境中,我们都会配置 redis 的 rdb 配置。
redis.conf 中关于 rdb 的所有配置:
save <seconds> <changes> stop-writes-on-bgsave-error rdbcompression rdbchecksum sanitize-dump-payload dbfilename rdb-del-sync-files dir
核心配置的常见问题解答:
q: save seconds changes 是什么意思?
a: 这个配置控制 redis 如何定期保存数据到磁盘。当指定的时间(秒)内,数据发生的变化次数超过或等于
q: 我看到了 stop-writes-on-bgsave-error,它的作用是什么?
a: 当此选项被设置为 yes 时,如果后台保存数据出现错误,redis 将停止所有写入操作。这是一种保护机制,确保在可能的磁盘问题或其他故障时,不再接受可能导致数据丢失的写操作。
当该选项被设置为 no 时,即使后台保存数据出现错误,redis 仍然会继续接受写入操作。
q: rdbcompression 能给我带来什么好处?
a: rdbcompression 设置为 yes 时,表示启用 rdbcompression, 启用 rdbcompression 会使redis在保存数据前先对其进行压缩,这样可以减少存储空间的使用。但这也意味着在数据加载时可能需要额外的 cpu 时间来解压。
q: 我在配置中看到了 rdbchecksum,这是什么意思?
a: rdbchecksum 决定是否在 rdb 文件末尾添加一个 crc64 校验和。这个校验和帮助检测 rdb 文件是否在传输或存储过程中受到损坏。如果你设置为yes,那么每次 redis 保存或加载 rdb 文件时,它都会计算并检查这个校验和,确保数据的完整性。
q: 什么是sanitize-dump-payload?我应该如何配置它?
a: 当你有一个redis数据备份(rdb文件)或者使用 restore 命令来导入数据时,你会希望这些数据是安全的,没有任何问题。但是,有些时候数据可能存在问题,这可能会导致 redis 在后续的操作中崩溃或者出现错误。
sanitize-dump-payload 这个配置项就是帮助你在加载数据时检查这些数据的安全性。
如果你设置为no,那么redis不会检查数据,这样会更快,但是风险也更大。
如果设置为yes,redis会检查所有的数据,确保它们是安全的,不会导致问题。这样更安全,但可能会稍微慢一些。
如果设置为clients,只有从客户端(比如你的应用程序)发来的数据会被检查,而从其它 redis 实例同步来的数据或rdb文件不会被检查。
q: rdb-del-sync-files 配置是做什么的?
a: 这个配置项决定是否在某些场景下删除与复制(replication)相关的rdb文件。
在 redis 的主从复制过程中,主节点需要生成 rdb 文件并将其发送给从节点,帮助从节点进行数据同步。在某些特定的安全环境中,一旦复制完毕,可能会要求尽快删除这些rdb文件。
rdb-del-sync-files 这个选项,当设置为 yes 时,并且主节点没有启用 rdb 和 aof持久化,redis 会自动删除这些与复制相关的 rdb 文件。
默认为no,这意味着与复制相关的rdb文件在同步后不会被自动删除。
q8: dbfilename 和 dir 分别指的是什么?
a: dbfilename 是 rdb 文件名(默认是 dump.rdb);dir 则是 rdb 文件存放的目录,默认值 ./(当前目录:redis服务器启动时的工作目录),但推荐指定一个固定的目录,例如:/var/redis/data/
注意:
-
上述的save 、dbfilename、以及 dir 指令配置是我们重点关注的,其他了解即可。
-
在更改 redis.conf 配置之后,我们需要重启 redis 服务,才能生效。
rdb 持久化的优缺点
优点
快速备份:rdb可以迅速为你创建一个数据的“快照”,这是一个备份文件,方便你存储或者迁移数据。
启动快:当redis重新启动时,rdb能帮助它更快速地加载数据,因为它直接读取一个完整的数据文件。
节省空间:与其他持久化方式相比,rdb的文件大小通常较小,因为它是经过压缩的。
缺点:
可能丢数据:因为rdb只是不时地保存一次数据快照,如果在两次保存之间redis出了问题,那中间的数据就可能会丢失。
有时会卡:在数据很多的情况下,创建 rdb 文件时可能会使服务器短暂地感觉有些卡顿。
卡顿的原因:尽管 redis 使用写时复制(copy-on-write, cow)技术来减少内存的复制,fork( ) 在大数据集上的调用仍然可能相当耗时。这是因为操作系统需要为子进程准备一个与父进程相同的虚拟内存空间。在这个准备过程中,即使不立即复制物理内存,操作系统也需要复制和设置父进程的页表,这在数据集很大时会占用相当一部分时间。fork( ) 的执行时间与服务器上的数据量大小成正比。因此在数据集较大时,fork 可能会有比较久的延迟才能返回,所以才造成的卡顿。
aof
aof是什么?
想象你正在写日记,每次有新的事件,你就写下来。aof 就像是 redis 的日记,记录了所有的写操作命令。
简单图解:

aof 的工作原理
基本机制和流程
redis 中的 aof 持久化方式旨在持续地保存服务器上的所有修改操作。每当执行一个会改变数据的命令时,redis 都会将该命令写入 aof 文件中。这样,当 redis 需要恢复数据时,只需执行 aof 文件中的命令就可以恢复到原来的状态。
aof 文件的生成
流程图

步骤说明:
aof 持久化的实现主要是以上三步:命令追加、文件写入、文件同步
- 命令追加: 将 redis 写操作命令追加到 aof_buf 缓冲区
- 文件写入: 周期性地将 aof_buf 缓冲区的命令写入 aof 文件的内核缓冲区。
- 文件同步:根据配置同步策略,将 aof 文件缓冲区的内容同步到磁盘。
其中文件同步策略 redis 提供了三种,分别是以下三种:
always:每次有命令写入时都立即同步。这提供了最高的数据安全性,但效率最低。
everysec:每秒同步一次。这是一个权衡安全性和效率的策略。最多只丢失 1 秒 的数据
no:让操作系统决定最佳的同步时间。这可能导致数据丢失,但提供了最高的效率。
aof 文件的载入
当 redis 服务器启动时,如果配置为使用 aof 持久化,它会检查 aof 文件的存在。如果找到 aof 文件,redis 会加载并执行其中的命令来恢复数据的。
这里顺带提个问题:假如 redis 的 rdb 和 aof 持久化都启用,redis 在载入数据的时候,是载入 aof 文件?还是 rdb 文件?
我直接说答案:redis 会优先载入 aof 文件来恢复数据,而不是 rdb 文件。这是因为 aof 文件通常包含了更完整的操作记录,从而能够恢复更完整的数据状态。而 rdb 文件是定时生成的数据快照,所以它可能没有记录到最后一次快照之后发生的所有更改。因此,使用 aof 文件恢复数据可以提供更高的数据完整性。
aof 重写
在了解了 aof 的工作原理之后,我们知道它是通过追加写操作命令到文件的方式来恢复数据的。但这会带来一个新的问题: 随着追加命令的不断增加,这个 aof 文件可能会变得很大和冗长。面对这样的问题,redis 提供了一个非常有效的优化手段,那就是 aof 重写。
aof重写是什么?
aof 重写,可以看作是对 aof文件 进行的一次“精简”操作。它的目的是减少aof文件的大小,并去除那些冗余的、不再必要的命令,使得该文件只包含恢复当前数据集所需的最小命令集。
为什么需要aof重写?
节省磁盘空间:随着操作的积累,原始aof文件可能会变得非常大。通过重写,我们可以减少文件的大小。
加速恢复速度:一个更小、更简洁的aof文件意味着在redis重启时,数据的恢复过程会更快。
aof 重写流程图:

步骤说明:
aof 重写主要有以下四步:
- redis 主进程 fork 子进程来进行 aof 的重写,生成 aof 文件。
- 在子进程进行 aof 重写的同时,redis 主进程将新的写操作命令写入 aof重写缓冲区
- 主进程将 aof 重写缓冲区的内容写入到新的 aof 文件中
- 使用新的 aof 文件替换旧的 aof 文件
这里思考一下:子进程 进行 aof 重写,具体怎么重写,是根据现有的 aof 文件进行重写还是其他方式?
子进程是通过读取 redis 当前的内存数据来进行重写的。假如: redis 数据库存在列表键 list = [a,b,c,d,e,f,g,h] ,在旧的 aof 文件中,可能有多个命令添加和删除这些元素。但在 aof 重写时,子进程只需要看 list键 的当前状态,然后生成一个简短的命令,如 rpush list a b c d e f g h,直接设置正确的值,避免了任何冗余操作。
aof 配置详解
我们只需要在 redis 配置文件 redis.conf 中搜索 append only mode 即可搜到 aof 配置项。
q: 我想启用 aof 模式,我应该怎么做?
a: 将 appendonly 设置为 yes。默认是 no。
q: 我想改变 aof 文件的名称,该怎么做?
a: 使用 appendfilename 选项。默认名称是 appendonly.aof。
q: 有哪些方式可以控制 aof 数据同步到磁盘的频率?
a: 使用 appendfsync 选项。你有三个选择:
always: 每次写操作后都同步。
everysec: 每秒同步一次。
no: 由操作系统决定何时同步。
默认设置是 everysec。
q: 当 redis 进行 aof 重写或快照保存时,我怎样避免主进程 fsync 的延迟?
a: 设置 no-appendfsync-on-rewrite 为 yes。默认是 no。
q: 我怎样自动触发 aof 文件重写?
a: 使用以下两个配置:
auto-aof-rewrite-percentage: aof 文件增长的百分比,达到此值则触发 aof 重写。例如,如果设置为100%,那么当 aof 文件的大小是上次重写后的两倍时,redis 会考虑触发自动重写。
auto-aof-rewrite-min-size: aof 文件大小门槛,超过此值即使增长的百分比小也会触发 aof 重写。
q: 如果 aof 文件在末尾被截断,redis怎么办?
a: 使用 aof-load-truncated 选项。如果设置为 yes,redis 尝试加载并启动,同时发出日志警告;如果为 no,redis 会中止并拒绝启动。默认是 yes。
aof 持久化的优缺点
优点:
不轻易丢数据:aof 记录了所有的写操作,所以即使服务器突然断电,数据丢失的机会也很小。
易于理解:aof是一个文本文件,里面就是一系列的命令,你可以打开查看。
出问题也能救:如果 aof 文件最后有点损坏,redis 也能够修复它,避免大量数据丢失。
缺点:
可能会慢一些:因为要不断写入操作,所以比 rdb 要慢一点。
文件可能很大:aof 会记录所有操作,所以文件可能迅速增大,占用更多空间。
恢复时间长:如果需要从 aof 文件中恢复数据,由于文件可能很大,所以这个过程可能会比较慢。
混合持久化
回顾一下,我们已经探讨了 redis 的 rdb 和 aof 持久化。rdb 提供快速的数据恢复,但可能有数据丢失风险;aof 保证了数据完整性,但文件可能过大,恢复速度较慢。那么,是否有一种既快速又可靠的方法?接下来,我们将介绍 redis 的混合持久化策略。
混合持久化是什么?
混合持久化是 redis 4.0 新引入的持久化策略,结合了 rdb 的快速恢复和 aof 的数据完整性的优点,它首先以 rdb 格式保存当前数据状态,然后继续以 aof 格式记录新的写操作,确保数据完整性并优化恢复速度。
简单图解

混合持久化的工作原理
在 aof 重写之前,rdb 和 aof 都是按照它们各自的持久化策略工作的。当 aof 重写被触发时,混合持久化才开始发挥作用:将当前的数据集会首先以rdb 格式写入新 aof 文件的顶部,然后再追加新的命令到文件的末尾。
混合持久化的工作流程图

步骤说明:
混合持久化的实现主要是靠主进程和子进程共同来完成的。
子进程:
子进程进行 aof 重写:
- 首先创建新的 aof 文件 appendonly.rdb
- 将 redis 当前的数据生成 rdb 快照写入 appendonly.rdb 文件的开始部分
主进程
- 主进程先将新的写操作命令写入 aof 重写缓冲区
-主进程将 aof 重写缓冲区的内容追加到 appendonly.rdb
文件的 rdb 数据的末尾 - 使用 appendonly.rdb 文件替换旧的 aof 文件
混合持久化的配置
q: redis 的混合持久化如何开启?
a: 将 aof-use-rdb-preamble 选项设置为 yes,并且要同时启用 rdb 和 aof 两种持久化。
混合持久化的 aof 重写与普通的 aof 重写的区别:
在不使用混合持久化的情况下,普通的 aof 重写是通过读取当前的内存数据并记录达到这一状态所需的最少命令来减少 aof 文件的大小的。
而混合持久化在 aof 重写时,会首先将当前数据集以 rdb 格式快照的形式写入新 aof 文件的开始位置,然后再追加新的写命令到文件末尾。
混合持久化的优缺点
优点:
更快的启动速度:混合持久化结合了rdb的速度优势,所以redis可以更快地重新启动,不用等待很久。
数据安全:利用aof的方式,即使服务器突然断电,也只会丢失极短的时间内的数据。
文件更小巧:因为混合持久化结合了 rdb 和 aof 的优势,所以文件大小和冗余度都可以得到控制。
两全其美:简单说,它就是rdb和aof的结合体,带来了两者的好处。
缺点:
稍微复杂:因为它结合了两种技术,所以处理起来比单一的 rdb 或 aof 要复杂一点。
可能占更多空间:在某些情况下,保存数据的文件可能会比只使用 rdb 或aof 的文件要大一些。
写入速度:可能会稍慢一些,特别是当数据需要经常被保存到硬盘时(比如当 appendfsync 配置为“always”时)
总结
在本系列文章中,我们深入探讨了 redis 的持久化机制。通过详细介绍 rdb、aof 以及混合持久化这三种主流的持久化方法,我们不仅学习了它们各自的工作机制和配置策略,还探讨了它们的优缺点,以帮助读者根据自己的实际需求选出合适的持久化方式。
- rdb 持久化以其高效的数据恢复速度和较小的性能开销脱颖而出,适合数据备份和灾难恢复场景。
- aof 持久化通过记录每个写操作确保了更高级别的数据安全性,尽管它可能导致文件体积增大和写入性能的轻微下降。
- 混合持久化模式结合了 rdb 的快速数据恢复能力和 aof 的数据安全性,提供了一种既快速又可靠的数据恢复解决方案。
所以大家在选择持久化策略时,需要考虑到数据安全性、恢复速度、以及系统性能三者之间的平衡。rdb 适合需要定期备份的场景,aof 适合对数据丢失有严格要求的应用,而混合持久化模式则是一种比较折中的方案,它结合了 rdb 的快速数据恢复能力和 aof 的数据安全性。
这里我又将 redis 的三种持久化方式的优缺点以及使用场景做了详细的对比:
| 持久化方式 | 优点 | 缺点 | 使用场景 |
|---|---|---|---|
| rdb | 1. 生成文件速度快。2. 恢复数据速度快。3. 磁盘空间占用少。 | 1. 数据丢失风险。2. 快照操作可能的性能下降。 | 1. 数据备份。2. 数据迁移。3. 灾难恢复时的快速数据恢复。 |
| aof | 1. 提供更高的数据安全性。2. 记录实际操作命令(可读性好)。3. 可以自定义保存频率。 | 1. 文件可能较大。2. 数据恢复速度较慢。 | 数据安全性要求高的场合 |
| 混合持久化 | 提供了数据安全和更快的数据恢复速度。 | 维护两种文件格式,增加磁盘占用空间。 | 快速的数据恢复和高数据安全性的场景。 |
最后
如果你对 linux c/c++ 编程,redis 等后端技术感兴趣或者想学习计算机基础相关的知识,不妨关注我的公众号「跟着小康学编程」。这里会持续更新的简单易懂的技术文章,也包括常见的技术面试题。
大家可以关注我 ,具体可访问 :关注小康微信公众号

另外,小康最近创建了一个技术交流群,专门用来探讨技术相关或者解答读者的问题。大家在阅读这篇文章的时候,如果觉得有问题的或者有不理解的知识点,欢迎大家加群询问。我能够解决的,尽量给大家回复。

发表评论