目录
一、为啥要进行redis持久化?
二、RDB持久化机制
1.RDB触发时机
- 手动触发
- 自动触发
2.代码演示
三、AOF 持久化机制
1.AOF 刷盘策略
2.AOF 重写(rewrite)
3. 代码演示
四、总结
一、为啥要进行redis持久化?
使用过redis的小伙伴们都清楚redis最常是被用来当作缓存存储在内存中的,但内存中的数据是不持久的,一旦重启redis服务器,如果没有将数据进行持久化(简单说就是存在硬盘里),原来内存中的数据就会被清空。
那么redis中的数据到底是存在内存中更好,还是存在硬盘中更好呢?答案是,成年人不做选择,两个都要😎!意思是:redis服务器重启时,从硬盘中加载数据到内存中,后续客户端要读取数据,redis就从内存中直接取。这就是redis持久化。
总的来说,redis持久化的目的就是为了防止redis服务器宕机、重启等操作导致数据丢失。
redis持久化机制主要又两种,即RDB和AOF。
二、RDB持久化机制
RDB——Redis Database,是指对redis内存中的数据进行定期备份的一种持久化操作。具体说就是定期把内存中的数据写到硬盘中,形成 “快照”。那么何为快照?
就像警察到了案发现场,相关工作人员就会立即拉起警戒线,将现场保护起来,快速拍照记录下来,后续办案的过程中就会对这些快照进行分析...
那么RDB所谓的定期备份,具体是如何实现的呢?定期备份分为两种,即手动触发和自动触发(后文详细介绍):
- 手动触发:通过执行save/bgsave命令,主动生成rdb快照文件。
- 自动触发:在配置文件中修改rdb持久化相关的配置。例如,每隔多长时间 / 每产生多少次修改进行一次快照。
1.RDB触发时机
- 手动触发
✅对于save命令:其执行流程就是直接生成快照,但此时要阻塞客户端上的所有命令,效率较低,不建议这么干。
✅对于bgsave命令:先了解,bg就是指background,也就明示了其是在后台进行的。听到这有些小伙伴就比较迷糊,redis不是单线程嘛,怎么就后台执行bgsave了?
在这其实redis是使用了多进程的并发执行的方式解决save阻塞问题的,父进程(执行命令的进程)通过创建子进程来执行生成rdb文件,进而形成“快照”。
对于bgsave的执行流程,咱们就得细说了,看图:
①:首先,redis判断是否存在其他正在工作(生成快照)的子进程,如果有,则直接返回;因为要将当前的数据形成快照,就直接包含了前面的快照,直接退出即可;
②:如果没有,父进程则通过fork这样的系统调用去创建一个子进程;
③:子进程负责写文件,形成“快照”;父进程则继续接收客户端发来的请求,正常响应。
④:子进程完成整体的持久化操作之后通知父线程 “活儿干完了”,父进程则更新一些统计信息,最后销毁子进程。
此时就有几个需要解释的疑问:
❓问题1:什么是fork?简单理解,fork就是复制进程的一个系统调用,我们不必理会其内部是怎样实现的,但需要明白的是,此处的复制进程,是指将父进程的进程控制块、虚拟地址空间(内存中的数据)以及文件描述符表都复制了一份。
❓问题2:假设父进程中的数据量很大,例如有100GB,全复制了不会造成空间开销大嘛?答案是 并不会,因为此处的复制拷贝并不是我们所想的一下全部复制下来,而是 “写时拷贝”。也就是,当子进程与父进程中的数据一致时,父进程和子进程中该数据所占用的是同一块地址,不会触发真正的拷贝。只有当双方中的某一方修改了该数据的值,就会触发真正意义上的物理地址的数据拷贝。况且redis中的绝大部分数据是不会进行修改的,通常是读操作 > 写操作。
- 自动触发
说到自动触发持久化,那总要有个条件才能“ 自动 ”吧?不可能随时都触发吧?那这个前提条件在哪呢?又回到配置文件的问题,像这种设置触发条件的一般都在相应的配置文件中。redis配置文件在/etc/redis/redis.conf下,在redis.conf文件中:
save <seconds> <changes>表达的含义是:在seconds秒内修改次数达到changes次才触发自动触发rdb快照。最下方的方框则是redis自动设置的触发条件,可以自行修改,但注意不要把rdb快照操作的频率调的太高,因为rdb持久化是一个高成本的操作,太频繁会导致性能降低。
对于rdb生成的快照的文件,在配置文件中也说明了:
- rdbchecksum yes :表示是否开启rdb持久化redis中的数据,yes开启,no关闭。
- dbfilename dump.rdb :表示生成的rdb快照文件的名称。
- rdb-del-sync-files no :表示生成的临时rdb同步文件,同步完之后,不自动删掉。默认为no,只有RDB和AOF都关闭时才生效。
- dir /var/lib/redis :表示rdb快照文件所处的相对路径。
2.代码演示
- 对于自动触发,使用save命令:
添加3条数据,再手动触发保存,使用vim命令,打开/etc/redis/var/lib/redis目录下的dump.rdb文件查看快照:
可以看到刚才设置的key1,key2,key3,由于rdb文件是以二进制的形式保存的,为什么不是按照我添加的顺序,因为redis中的全局key-value是以哈希表的形式存储在一起的,遍历下来顺序就肯会发生改变。
- 对于自动触发,需要达到redis.conf配置文件中的触发条件即可触发,也可面对不同的业务去修改相应的配置项。此处不演示。
三、AOF 持久化机制
AOF 全称 Append Only File,和 RDB 快照思路完全不同:RDB 保存某一瞬间内存里全部的数据(二进制快照),AOF 是记录每一条写操作命令,类似 MySQL 的 binlog,客户端执行的写命令会追加写入 AOF 日志文件。Redis 重启的时候,会读取 AOF 文件,重新回放里面的命令,把数据恢复出来。
Redis 默认 AOF 是关闭状态的,所以需要修改配置文件开启。不过RDB 和 AOF 可以同时开启,并不会互相覆盖;只是 Redis 重启恢复数据时,会优先加载 AOF 文件。
1.AOF 刷盘策略
AOF 并不是执行一条命令就直接写到硬盘。写命令先放到内存缓冲区,再根据配置策略,把缓冲区的数据刷入磁盘,对应配置项 appendfsync,一共 3 种策略:
- appendfsync always:每一条写命令,立刻刷盘。安全性最高,几乎不会丢数据,但是磁盘 IO 非常频繁,性能很差,生产环境很少使用。
- appendfsync everysec(默认):每隔 1 秒把缓冲区数据刷盘。最多丢失 1 秒内的数据,在性能和数据安全之间做了平衡,是生产最常用方案。
- appendfsync no:不主动刷盘,交给操作系统自己调度什么时候写入磁盘。Redis 性能最好,但是宕机时丢失数据风险最大。
简单理解:刷盘频率越高,数据越安全,性能越差;刷盘频率越低,性能越好,丢数据风险越高。
2.AOF 重写(rewrite)
AOF 会持续记录所有写命令,如果同一个 key 反复修改,AOF 文件会越来越大,里面存在大量冗余命令。 举个例子:
set num 1 set num 2 set num 3AOF 里面存了 3 条 set 命令,其实只保留最后一条set num 3就可以恢复数据,前面两条都是多余的。
AOF 重写,就是 Redis 自动清理冗余命令,生成精简的新 AOF 文件。
⚠️重点:重写不是读取旧 AOF 文件去精简,而是 fork 子进程,直接读取当前内存里的数据,生成最少的恢复命令。
重写分为两种:
- 手动触发:bgrewriteaof命令,后台执行重写
- 自动触发:配置文件设置大小阈值,AOF 文件达到条件自动触发重写
重写过程也是 fork 子进程完成:父进程正常处理客户端请求,子进程负责生成新的精简 AOF 文件,不会阻塞 Redis 服务。子进程生成新文件之后,Redis 会切换到新 AOF 文件,旧文件就可以丢弃。如图:
3. 代码演示
AOF 是文本文件,里面记录的是 Redis 命令,我们在 redis-cli 写入测试数据:
set name lisi set age 18 hset user id 1 name wangwu写入之后,这些写命令会被追加到 AOF 文件中。
查看aof文件:
说明:本文不演示修改配置开启 AOF,配置修改操作不当容易引发异常,理解原理即可。
四、总结
到这里,RDB 和 AOF 两种持久化机制就都过了一遍。最后用一张表格把两者的核心差异放在一起对比,方便记忆和面试复习:
| 对比项 | RDB | AOF |
|---|---|---|
| 存储内容 | 某一刻的内存数据快照(二进制) | 一条条写操作命令(文本) |
| 数据丢失 | 宕机可能丢失上一次快照之后的全部数据 | 默认最多丢失 1 秒数据 |
| 文件大小 | 体积小 | 原始文件偏大,依靠重写压缩 |
| 恢复速度 | 快,直接加载二进制 | 慢,需要逐条回放命令 |
| 恢复优先级 | 低 | 高(两者同时开启优先加载 AOF) |
简单总结一下:RDB 适合做定期的数据备份,文件小、恢复快;AOF 更注重数据安全,丢数据少,但文件大、恢复慢。实际生产环境中,两者通常会同时开启,用 RDB 兜底备份,用 AOF 保证数据尽量不丢。
持久化本质只是 Redis 的兜底保障。Redis 本身是内存数据库,它的核心优势是高速读写,持久化并不是用来替代 MySQL 这类数据库做持久化存储的。我们使用持久化,只是为了防止服务宕机、重启时内存数据丢失,保证故障之后数据可以恢复。