Redis详解:RDB持久化和AOF持久化

一、RDB持久化

RDB是Redis默认的持久化方案。在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中,即在指定目录下生成一个dump.rdb文件,Redis重启会通过加载dump.rdb文件恢复数据

RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中

在这里插入图片描述

RDB持久化功能所生成的RDB文件是一个经过压缩的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态

在这里插入图片描述

1、RDB文件的创建与载入

有两个Redis命令可以用于生成RDB文件,一个是SAVE,另一个是BGSAVE

SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求

BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求

RDB文件的载入工作是在服务器启动时自动执行的,所以Redis并没有专门用于载入RDB文件的命令,只要Redis服务器在启动时检测到RDB文件存在,它就会自动载入RDB文件

因为AOF文件的更新频率通常比RDB文件的更新频率高,所以:

  • 如果服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据库状态
  • 只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据库状态

在这里插入图片描述

创建RDB文件的实际工作由rdb.c/rdbSave函数完成,载入RDB文件的实际工作由rdb.c/rdbLoad函数完成

在这里插入图片描述

1)、SAVE命令执行的服务器状态

当SAVE命令执行时,Redis服务器会被阻塞,所以当SAVE命令正在执行时,客户端发送的所有命令请求都会被阻塞。只有在服务器执行完SAVE命令、重新开始接受命令请求之后,客户端发送的命令才会被处理

2)、BGSAVE命令执行时的服务器状态

因为BGSAVE命令的保存工作是由子进程执行的,所以在子进程创建RDB文件的过程中,Redis服务器仍然可以继续处理客户单的命令请求,但是在BGSAVE命令执行期间,服务器处理SAVE、BGSAVE、BGREWRITEAOF三个命令的方式会和平时有所不同

1)在BGSAVE命令执行期间,客户端发送的SAVE命令会被服务器拒绝,服务器禁止SAVE命令和BGSAVE命令同时执行是为了避免父进程和子进程同时执行两个rdbSave调用,防止产生竞争条件

2)在BGSAVE命令执行期间,客户端发送的BGSAVE命令会被服务器拒绝,因为同时执行两个BGSAVE命令也会产生竞争条件

3)BGREWRITEAOF和BGSAVE两个命令不能同时执行:

  • 如果BGSAVE命令正在执行,那么客户端发送的BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行
  • 如果BGREWRITEAOF命令正在执行,那么客户端发送的BGSAVE命令会被服务器拒绝

因为BGREWRITEAOF和BGSAVE两个命令的实际工作都由子进程执行,所以这两个命令在操作方面并没有什么冲突的地方,不能同时执行它们只是一个性能方面的考虑——并发出两个子进程,并且这两个子进程都同时执行大量的磁盘写入操作

3)、RDB文件载入时的服务器状态

服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成为止

2、自动间隔性保存

用户可以通过save选项设置多个保存条件,但只要其中任意一个条件被满足,服务器就会执行BGSAVE命令

如果向服务器提供以下配置:

save 900 1
save 300 10
save 60 10000

那么只要满足以下三个条件中的任意一个,BGSAVE命令就会被执行:

  • 服务器在900秒之内,对数据库进行了至少1次修改
  • 服务器在300秒之内,对数据库进行了至少10次修改
  • 服务器在60秒之内,对数据库进行了至少10000次修改

1)、设置保存条件

当Redis服务器启动时,用户可以通过指定配置文件或者传入启动参数的方式设置save选项,如果用户没有主动设置save选项,那么服务器会为save选项设置默认条件:

save 900 1
save 300 10
save 60 10000

服务器程序会根据save选项所设置的保存条件,设置服务器状态redisServer结构的saveparams属性:

struct redisServer{
	
    // 记录了保存条件的数组
    struct saveparam *saveparams;
    
    // ...
    
};

saveparams属性是一个数组,数组中的每个元素都是一个saveparam结构,每个saveparam结构都保存了一个save选项设置的保存条件:

struct saveparam{
	
    // 秒数
    time_t seconds;
    
    // 修改数
    int changes;
    
};

在这里插入图片描述

2)、dirty计数器和lastsave属性

  • dirty计数器记录距离上次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态进行了多少次修改
  • lastsave属性是一个UNIX时间戳,记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间
struct redisServer{
	
    // 修改计数器
    long long dirty;
    
    // 上一次执行保存的时间
    time_t lastsave;
    
    // ...
    
};

当服务器成功执行一个数据库修改命令之后,程序就会对dirty计数器进行更新:命令修改了多少次数据库,dirty计数器的值就增加多少

3)、检查保存条件是否满足

Redis的服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查save选项所设置的保存条件是否已经满足,如果满足的话,就执行BGSAVE命令

程序会遍历并检查saveparams数组中的所有保存条件,只要有任意一个条件被满足,那么服务器就会执行BGSAVE命令

二、AOF持久化

AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的,默认不开启

在这里插入图片描述

1、AOF持久化的实现

1)、命令追加

当AOF持久化功能处于打开状态时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的末尾

struct redisServer{
	
    // AOF缓冲区
    sds aof_buf;
    
    // ...
    
};

2)、AOF文件的写入与同步

Redis的服务器进程就是一个事件循环,这个循环中的文件事件负责接收客户端的命令请求,以及向客户端发送命令回复,而时间事件则负责执行serverCron函数这样需要定时运行的函数

因为服务器在处理文件事件时可能会执行写命令,使得一些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里面

在这里插入图片描述

appendfsync选项的默认值为everysec

AOF持久化的效率和安全性

服务器配置appendsync选项的值直接决定AOF持久化功能的效率和安全性

  • appendsync的值为always时,服务器在每个时间循环都要将aof_buf缓冲区的所有内容写入到AOF文件,并且同步AOF文件,所有always的效率是appendsync最慢的一个,但是也是最安全的,宕机出现,AOF持久化也只会丢失一个事件循环中所产生的命令数据

  • appendsync的值为everysec时,服务器在每个事件循环都要将aof_buf缓冲区的所有内容写入到AOF文件,并且每隔一秒就要在子线程中对AOF文件进行一次同步。效率上足够快,并且就算出现故障宕机,数据库也只会丢失一秒钟的命令数据

  • appendsync的值为no时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件中,至于何时对AOF文件进行同步,则由操作系统控制。因此该模式速度最快,不过因为这种模式会在缓存中积累一段时间的写入数据,所以单次同步时长是最长的。从平摊的角度上看,no模式和everysec模式的效率类似。但是宕机丢失的数据最多

2、AOF文件的载入与数据还原

Redis读取AOF文件并还原数据库状态的详细步骤如下:

1)创建一个不带网络连接的伪客户端:因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样

2)从AOF文件中分析并读取出一条写命令

3)使用伪客户端执行被读出的写命令

4)一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被处理完毕为止

在这里插入图片描述

3、AOF重写

为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重写功能。通过该功能,Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库状态相同,但新AOF文件不会包含任何浪费空间的冗余命令,所以新AOF文件的体积通常会比旧AOF文件的体积要小很多

1)、AOF文件重写的实现

AOF重写功能的实现原理:首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令

aof_rewrite函数生成的新AOF文件只包含还原当前数据库所必须的命令,所以新AOF文件不会浪费任何硬盘空间

2)、AOF后台重写

aof_rewrite函数可以很好地完成创建一个新AOF文件的任务,但是因为这个函数会进行大量的写入操作,所以调用这个函数的线程将被长时间阻塞,因为Redis服务器使用单个线程来处理命令请求,所以如果由服务器直接调用aof_rewrite函数的话,那么在重写AOF文件期间,服务器将无法处理客户端发来的命令请求

Redis将AOF重写程序放到子进程里执行,这样做可以同时达到两个目的:

  • 子进程进行AOF重写期间,服务器进程可以继续处理命令请求
  • 子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性

Redis服务器设置了一个AOF重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用,当Redis服务器执行完一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区

在子进程执行AOF重写期间,服务器进程需要执行以下三个工作:

1)执行客户端发来的命令

2)将执行后的写命令追加到AOF缓冲区

3)将执行后的写命令追加到AOF重写缓冲区

在这里插入图片描述

这样以来可以保证:

  • AOF缓冲区的内容会定期被写入和同步到AOF文件,对现有AOF文件的处理工作会如常进行
  • 从创建子进程开始,服务器执行的所有写命令都会被记录到AOF重写缓冲区里面

当子进程完成AOF重写工作之后,它会向父进程发送一个信号,父进程在接收到该信号之后,会调用一个信号处理函数,并执行以下工作:

1)将AOF重写缓冲区中的所有内容写入到新AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致

2)对新的AOF文件进行改名,原子地覆盖现有的AOF文件,完成新旧两个AOF文件的替换

在这里插入图片描述

三、RDB和AOF优缺点对比

1、RDB的优点

  • RDB是一个快照文件,数据很紧凑,它保存了Redis在某个时间点上的数据集,体积比较小
  • RDB适合用于灾难恢复,因为它只有一个文件,而且体积小,方便拷贝
  • RDB可以最大化Redis的性能:父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘I/O操作
  • RDB在恢复大数据集时的速度比AOF的恢复速度要快

2、RDB的缺点

  • 服务器故障时候会丢失数据。虽然可以调整RDB文件的保存频率,但是要保存整个数据集的快照,也不可能太频繁。所以使用RDB如果服务器出现故障可能出现丢失几分钟的数据
  • 每次保存RDB的时候,Redis都要fork()出一个子进程,并由子进程来进行实际的持久化工作。在数据集比较庞大时,fork()可能会非常耗时,造成服务器在某某毫秒内停止处理客户端;如果数据集非常巨大,并且CPU时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒

3、AOF的优点

  • AOF的默认策略为每秒钟fsync一次,在这种配置下,Redis仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据(fsync会在后台线程执行,所以主线程可以继续努力地处理命令请求),也可以根据实际情况设置fsync的策略
  • AOF文件是一个只进行追加操作的日志文件,因此对AOF文件的写入不需要进行seek,即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机等等),redis-check-aof工具也可以轻易地修复这种问题
  • Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为Redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作
  • AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析也很轻松。导出AOF 文件也非常简单:举个例子,如果不小心执行了 FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除AOF文件末尾的FLUSHALL命令,并重启Redis,就可以将数据集恢复到FLUSHALL执行之前的状态

4、AOF的缺点

  • 对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积
  • 根据所使用的fsync策略,AOF的速度可能会慢于RDB。在一般情况下,每秒fsync的性能依然非常高,而关闭fsync可以让AOF的速度和RDB一样快,即使在高负荷之下也是如此。不过在处理巨大的写入载入时,RDB可以提供更有保证的最大延迟时间

参考:https://cloud.tencent.com/developer/news/307359

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
RDBRedis Database)和AOF(Append-Only File)是Redis中两种常见的持久化方式,它们有以下区别: 1. RDB持久化RDB是将Redis数据库在某个时间点的数据快照保存到硬盘上的一种方式。它通过fork一个子进程来完成持久化操作,首先将数据写入一个临时文件,然后用这个临时文件替换上一个RDB文件,从而实现数据的持久化RDB方式适合用于备份、灾难恢复和数据库迁移等场景。 2. AOF持久化AOF是通过将Redis的写命令追加到文件的末尾来记录数据库的操作。Redis重启时,通过重新执行AOF文件中的命令来恢复数据库状态。相比于RDB方式,AOF可以提供更高的数据安全性,因为它记录了每个写操作的历史,可以保证在Redis异常退出或宕机时不会丢失数据。AOF方式适合用于数据持久化和实时备份等场景。 3. RDB的优点:RDB方式对于数据恢复速度较快,在大规模数据恢复时比AOF更高效。由于RDB是一个紧凑的二进制文件,相对于AOF文件来说更小,可以节省存储空间。此外,RDB方式对Redis的性能影响较小。 4. AOF的优点:AOF方式可以提供更高的数据安全性,因为它记录了每个写操作的历史,可以保证在Redis异常退出或宕机时不会丢失数据。AOF文件是一个文本文件,易于理解和修改。 总结来说,RDB方式适合于备份和灾难恢复,而AOF方式适合于数据持久化和实时备份。在选择持久化方式时,需要根据实际需求进行权衡和选择。另外,也可以同时使用RDBAOF两种方式,以提供更好的数据安全性和灾难恢复能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邋遢的流浪剑客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值