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

posted @ 2021-04-25 20:09  欢乐豆123  阅读(588)  评论(0编辑  收藏  举报