Redis的持久化方式
Redis的持久化方式
概要
什么是持久化(Persistence)?即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
一、Redis为什么要持久化?
Redis是一个内存数据库,所有的数据将保存在内存中,这与传统的MySQL等关系型数据库直接把数据保存到硬盘相比,Redis的读写效率非常高。
但是保存在内存中也有一个很大的缺陷,一旦断电或者宕机,内存数据库中的内容将会全部丢失。为了弥补这一缺陷,Redis提供了把内存数据持久化到硬盘文件,以及通过备份文件来恢复数据的功能。
Redis官方提供了不同级别的持久化方式:RDB 持久化和 AOF持久化。
二、RDB持久化
1. RDB持久化原理
RDB(Redis DataBase)持久化是一种基于快照的持久化方式。
在指定的时间间隔内,如果满足一定条件(如某段时间内发生的写操作次数),Redis会生成一个包含当前内存数据的RDB文件(是一个二进制文件,默认名称为dump.rdb,可修改)。这个RDB文件可以用于数据恢复或备份。RDB持久化提供了较高的数据压缩率和快速的数据加载速度,但可能存在一定程度的数据丢失。
因此,可以这么描述:RDB持久化方式就是在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
2. RDB持久化触发方式
1)手动触发:使用SAVE或BGSAVE命令。
- SAVE是同步命令,执行过程中会阻塞其他请求。
- BGSAVE是异步命令,主进程会fork一个子进程,进行异步持久化,持久化过程中主进程仍然可以处理其他请求。
创建RDB文件的实际工作由rdb.c/rdbSave函数完成,SAVE命令和BGSAVE命令会以不同的方式调用这个函数,通过以下伪代码可以明显地看出这两个命令之间的区别:
1 def SAVE(): 2 # 创建RDB文件 3 rdbSave() 4 5 def BGSAVE(): 6 # 创建子进程 7 pid = fork() 8 9 if pid == 0: 10 11 # 子进程负责创建RDB文件 12 rdbSave() 13 14 # 完成之后向父进程发送信号 15 signal_parent() 16 17 elif pid > 0: 18 19 # 父进程继续处理命令请求,并通过轮询等待子进程的信号 20 handle_request_and_wait_signal() 21 22 else: 23 # 处理出错情况 24 handle_fork_error()
2)自动触发:在配置文件中设置触发条件,redis.conf配置如下:
1 # 900s内至少有一次写操作 2 save 900 1 3 # 300s内至少有10次写操作 4 save 300 10 5 # 60s内至少有10000次写操作 6 save 60 10000
3)关闭Redis时触发:Redis在关闭服务时会自动触发一次RDB持久化。
4)主从同步时触发:当从节点连接到主节点时,主节点会触发一次RDB持久化,并将生成的RDB文件发送给从节点进行同步。
3. RDB持久化优缺点
1)RDB持久化具有以下优点:
- 高性能:由于采用子进程进行磁盘操作,主进程无需进行磁盘IO,保证了Redis的高性能。
- 快速恢复:RDB文件包含了某一时刻的完整数据快照,可以快速恢复数据。
- 更小的存储空间:RDB文件经过压缩,占用较小的磁盘空间。
2)RDB持久化的缺点包括:
- 数据丢失:由于RDB持久化是基于时间间隔的,可能存在一定程度的数据丢失。
- 无法做到实时性:RDB方式无法做到实时或秒级持久化。因为 RDB 使用 fork() 产生子进程进行数据的持久化,而fork操作是一个耗时操作,无法做到实时性。
- 子进程占用内存:在生成RDB文件过程中,子进程会占用和主进程相同的内存空间,可能导致内存不足的问题。
三、 AOF持久化
除了RDB持久化功能之外,Redis还提供了AOF (Append Only File)持久化功能。与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。即每执行一个写命令,就会把该命令写到日志文件里。
如下图:
1. AOF持久化原理
AOF(Append Only File)持久化是一种基于日志的持久化方式。Redis将所有的写操作命令追加到一个AOF文件中。当Redis重新启动时,可以通过重放AOF文件中的命令来恢复数据。
2. AOF持久化配置
AOF持久化的配置主要包括以下几个方面:
1)启用AOF持久化:在配置文件中设置appendonly yes。
1 # 开启aof持久化 2 appendonly yes 3 4 # aof文件名 5 appendfilename "appendonly.aof"
2)AOF文件同步策略:在配置文件中设置appendfsync选项。可选值包括:
- always(同步写回):每次写操作都同步到磁盘,保证最高的数据安全性,但性能较差。
- everysec(每秒写回):每秒同步一次磁盘,提供较好的数据安全性和性能平衡。
- no(操作系统自动写回):由操作系统决定何时同步磁盘,性能最好,但数据安全性较差。
1 # 持久化策略,always表示每次写入都进行持久化 9 appendfsync always
3)AOF重写策略:在redis.conf文件中进行配置,控制AOF重写的触发条件。
1 # 指定在执行BGSAVE或BGREWRITEAOF命令时是否禁用AOF文件同步。默认为yes,表示禁用同步。 2 no-appendfsync-on-rewrite yes 3 4 # 指定AOF文件大小增长到原始大小的百分比时进行重写。 5 # 默认为100,表示AOF文件大小增长到原始大小的两倍时进行重写。 6 auto-aof-rewrite-percentage 100 7 8 # 指定进行AOF重写的最小AOF文件大小。默认为64mb。 9 auto-aof-rewrite-min-size 64
3. AOF持久化的工作流程
大致可以描述为:开启 AOF 持久化后,每执行一条会更改 Redis 中数据的命令,Redis 就会将该命令写入到 AOF 缓冲区 server.aof_buf 中,然后再写入到 AOF 文件中(此时还在系统内核缓存区未同步到磁盘),最后再根据持久化方式( fsync策略)的配置来决定何时将系统内核缓存区的数据同步到硬盘中的。只有同步到磁盘中才算持久化保存了,否则依然存在数据丢失的风险,比如说:系统内核缓存区的数据还未同步,磁盘机器就宕机了,那这部分数据就算丢失了。AOF 文件的保存位置和 RDB 文件的位置相同,都是通过 dir 参数设置的,默认的文件名是 appendonly.aof。
AOF 持久化功能的实现可以简单分为 5 步:
1)命令追加(append)
当AOF 持久化功能打开时,所有的写命令会以协议格式追加到 AOF 缓冲区末尾。
2)文件写入(write)
将 AOF 缓冲区的数据写入到 AOF 文件中。这一步需要调用write函数(系统调用),write将数据写入到了系统内核缓存区之后直接返回了(延迟写)。注意!!!此时并没有同步到磁盘。
3)文件同步(fsync)
AOF 缓冲区根据对应的持久化方式( fsync 策略)向硬盘做同步操作。这一步需要调用 fsync 函数(系统调用), fsync 针对单个文件操作,对其进行强制硬盘同步,fsync 将阻塞直到写入磁盘完成后返回,保证了数据持久化。
AOF持久化提供三种回写磁盘的策略,就是上面提到的AOF持久化配置中的AOF文件同步策略。
4)文件重写(rewrite)
随着写操作的不断进行,AOF文件会不断增长,占用更多的磁盘空间和网络带宽。为了减小AOF文件的大小,Redis提供了AOF重写功能。
AOF重写会创建一个新的AOF文件,只包含当前内存中数据的最小命令集(能重建当前数据集的最小操作命令的集合)。在重写过程中,Redis会继续将新的写操作追加到原始AOF文件中。当重写完成后,新的AOF文件将替换原始AOF文件。然后开始把数据写到新文件上。
AOF重写的触发方式分为手动触发和自动触发。
4.1)手动触发
可以手动执行bgrewriteaof命令,触发AOF重写。
1 redis> bgrewriteaof
手动触发的流程如下图:
4.2)自动触发
系统自动触发 AOF 重写机制可以通过配置文件中的 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 参数来控制 。
系统自动触发 AOF 重写机制还需要满足以下条件:
- 当前没有正在执行 BGSAVE 或 BGREWRITEAOF 的子进程
- 当前没有正在执行 SAVE 的主进程
- 当前没有正在进行集群切换或故障转移
5)重启加载(load):当 Redis 重启时,可以加载 AOF 文件进行数据恢复。
4. AOF持久化优缺点
1)AOF持久化的优点
- 更高的数据安全性:根据同步策略的选择,AOF持久化可以保证较高的数据安全性。
- 更好的容错性:即使AOF文件存在部分损坏,仍可以恢复大部分数据。
2)AOF持久化的缺点
- 较大的存储空间:与RDB持久化相比,AOF文件通常较大,占用较多磁盘空间。
- 数据加载速度较慢:由于需要重放AOF文件中的命令,数据恢复速度相对较慢。
五、混合持久化
混合持久化结合了RDB持久化和AOF持久化的优点,可以在保证数据安全性的同时,提供较快的数据加载速度。
在这种持久化方式下,Redis会同时生成RDB文件和AOF文件。当Redis重新启动时,优先使用AOF文件恢复数据,以确保数据的完整性。混合持久化适用于对数据安全性和性能要求较高的场景。
六、RDB和AOF的对比
1. RDB的优势
1)RDB文件存储压缩后的二进制数据,文件小,适合备份和灾难恢复。恢复速度快,因为不需要逐条执行命令。
2)AOF文件通常比RDB大很多,需要定期重写。重写期间,写入命令可能会消耗大量内存。
2. AOF的优势
1)AOF数据安全性更高,支持秒级持久化,丢失数据少。
2)AOF文件易于理解和解析,可以手动编辑来修复数据问题。
3)RDB格式随着Redis版本变化,存在兼容性问题,而AOF格式更加直观和灵活。
七、总结
1. RDB 适合定期备份和恢复,不怕丢失少量数据的场景。
2. AOF 适合对数据一致性和持久性要求较高的场景,但会带来性能和磁盘空间的开销。不建议单独使用 AOF,因为时不时地创建一个 RDB 快照可以进行数据库备份、更快的重启以及解决 AOF 引擎错误。
3. RDB + AOF 适合在性能和持久化之间寻找平衡的应用。
4. 无持久化 适合仅用于缓存的场景,不需要数据持久化。
参考链接:
https://segmentfault.com/a/1190000002906345
http://redisdoc.com/topic/persistence.html
https://www.cnblogs.com/xuwenjin/p/9876432.html
https://juejin.cn/post/6844903655527677960
https://javaguide.cn/database/redis/redis-persistence.html