Redis 的持久化 RDB和 AOF

Redis 的持久化 RDB和 AOF

1. 简介

Redis 是一个快速的 key-value 形式的 内存数据库。同时Redis支持RDBAOF两种持久化机制,持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复。

2. 持久化

2.1 RDB


RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发自动触发

2.1.1 如何触发

手动触发

手动触发分为两个命令 save 和 bgsave 。

  • save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用
  • bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。

因为bgsave命令是针对 save命令做了优化的,所以Redis现在内部RDB的操作都是使用了bgsave的方式。

自动触发

Redis 内部会进行自动触发RDB操作。

  • 1)使用save相关配置,如“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave。
  • 2)如果从节点执行全量复制操作,主节点自动执行bgsave生成RDB文319件并发送给从节点
  • 3)执行debug reload命令重新加载Redis时,也会自动触发save操作。
  • 4)默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则自动执行bgsave。

在redis.conf 中有如下配置:
**

  • save:这里是用来配置触发 Redis的 RDB 持久化条件,也就是什么时候将内存中的数据保存到硬盘。比如“save m n”。表示m秒内数据集存在n次修改时,自动触发bgsave(这个命令下面会介绍,手动触发RDB持久化的命令)

默认如下配置:

save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存
save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存
save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存

当然如果你只是用Redis的缓存功能,不需要持久化,那么你可以注释掉所有的 save 行来停用保存功能。可以直接一个空字符串来实现停用:save “”

  • stop-writes-on-bgsave-error :默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了
  • rdbcompression ;默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。
  • rdbchecksum :默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
  • dbfilename :设置快照的文件名,默认是 dump.rdb
  • dir:设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。

也就是说通过在配置文件中配置的 save 方式,当实际操作满足该配置形式时就会进行 RDB 持久化,将当前的内存快照保存在 dir 配置的目录中,文件名由配置的 dbfilename 决定。

2.1.2 处理流程


下图是 bgsave 的处理流程图。
![image.png](https://img-blog.csdnimg.cn/img_convert/2f0ae585827c197a548ef49465db4b67.png#align=left&display=inline&height=454&margin=[object Object]&name=image.png&originHeight=695&originWidth=872&size=153100&status=done&style=none&width=569)

  1. 执行 bgsave 命令 ,Redis 的主进程进行处理,判断当前是否存在子进程正在进行 RDB/AOF 操作,直接返回。
  2. 父进程 执行 fork操作 创建子进程,fork 过程中父进程会阻塞,fork属于操作系统中的重操作。通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗 时,单位为微秒。
  3. 父进程 fork完之后 可以继续处理其他命令。
  4. 子进程会按照一定规则 生成 RDB文件 ,并对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的 时间,对应info统计的rdb_last_save_time选项。
  5. 进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence下的rdb_*相关选项。

> 生成目录:RDB文件保存在dir配置指定的目录下,文件名通过dbfilename配置指定。可以通过执行config set dir{newDir}和config set dbfilename{newFileName}运行期动态执行,当下次运行时RDB文件会保存到 新目录> 。
> 压缩: Redis默认采用LZF算法对生成的RDB文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数config set rdbcompression{yes|no}动态修改。 压缩会消耗CPU,但是会大幅降低 RDB文件体积。

2.1.3 RDB 的优缺点

RDB 的优点
  • RDB是一个按照指定规则压缩的紧凑二进制文件。代表Redis在某个时间点的数据快照,非常适用于备份,全量复制等。
  • RDB 文件的加载远远快于 AOF文件。

RDB的缺点
  • RDB 的执行成本比较高,因为 fork属于重量级操作。RDB 没法做到实时持久化/秒级持久化.
  • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本``Redis``服务无法兼容新版``RDB``格式的问题。

针对这个问题,redis 还有另外一种 持久化方法 AOF。

2.2 AOF


AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

2.2.1 触发方式

自动触发

在redis.conf 配置中可以看到:

  • appendonly:默认值为no,也就是说redis默认使用的是rdb方式持久化,如果想要开启 AOF 持久化方式,需要将 appendonly 修改为 yes。
  • appendfilename :aof文件名,默认是"appendonly.aof"
  • **appendfsync:**aof持久化策略的配置。 通常有三种方式。

no 表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全;
always 表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低;
everysec 表示每秒执行一次fsync,可能会导致丢失这1s数据。通常选择 everysec ,兼顾安全性和效率

  • no-appendfsync-on-rewrite:在aof重写或者写入rdb文件的时候,会执行大量IO,此时对于everysec和always的aof模式来说,执行fsync会造成阻塞过长时间,no-appendfsync-on-rewrite字段设置为默认设置为no。如果对延迟要求很高的应用,这个字段可以设置为yes,否则还是设置为no,这样对持久化特性来说这是更安全的选择。 设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes。Linux的默认fsync策略是30秒。可能丢失30秒数据。默认值为no。
  • auto-aof-rewrite-percentage默认值为100。aof自动重写配置,当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写,即当aof文件增长到一定大小的时候,Redis能够调用bgrewriteaof对日志文件进行重写。当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写过程。
  • auto-aof-rewrite-min-size64mb。设置允许重写的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写。
  • aof-load-truncated:aof文件可能在尾部是不完整的,当redis启动的时候,aof文件的数据被载入内存。重启可能发生在redis所在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项,出现这种现象 redis宕机或者异常终止不会造成尾部不完整现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择的是yes,当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-check-aof修复AOF文件才可以。默认值为 yes。

2.2.2 处理流程


AOF的工作流程操作:命令写入 (append)、文件同步(sync)、文件重写(rewrite)、重启加载 (load),如图。
![image.png](https://img-blog.csdnimg.cn/img_convert/7d786a1113aac41879c1fb8ada1f347e.png#align=left&display=inline&height=574&margin=[object Object]&name=image.png&originHeight=765&originWidth=721&size=136679&status=done&style=none&width=541)

  1. 所有的写入命令会追加到aof_buf(缓冲区)中。
  2. AOF缓冲区根据对应的策略向硬盘做同步操作。
  3. 随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
  4. 当Redis服务器重启时,可以加载AOF文件进行数据恢复。

> AOF 写入的都是文本命令。例如 set key value 等。

1)AOF为什么直接采用文本协议格式?可能的理由如下:
·文本协议具有很好的兼容性。
·开启AOF后,所有写入命令都包含追加操作,直接采用协议格式,避免了二次处理开销。
·文本协议具有可读性,方便直接修改和处理。
2)AOF为什么把命令追加到aof_buf中?
Redis使用单线程响应命令,如果每次写AOF文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负
载。先写入缓冲区aof_buf中,还有另一个好处,Redis可以提供多种缓冲区 同步硬盘的策略,在性能和安全性方面做出平衡。

2.2.3 AOF 重写

为什么需要重写?


随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入AOF重写机制压缩文件体积。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。

重写的优点
  1. 进程内已经超时的数据不再写入文件。
  2. 旧的``AOF``文件含有无效命令,如del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保 留最终数据的写入命令。
  3. 多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。
  4. 更小的AOF文件可以被更快的加载

重写的触发

AOF重写过程可以手动触发和自动触发

  • 手动触发:直接调用bgrewriteaof命令。
  • 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机。

  1. auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认 为64MB。
  2. auto-aof-rewrite-percentage:代表当前AOF文件空间 (aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值 默认为 100,为2倍。
  3. 自动触发时机=aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size aof_base_size)/aof_base_size>=auto-aof-rewrite- percentage .

aof文件大于64MB并且为上次重写后AOF文件的2倍。

其中aof_current_sizeaof_base_size可以在info Persistence统计信息中查看。

重写的工作流程


![image.png](https://img-blog.csdnimg.cn/img_convert/3a9b61d8335a654e32d47dcc6b5c5529.png#align=left&display=inline&height=569&margin=[object Object]&name=image.png&originHeight=758&originWidth=742&size=161333&status=done&style=none&width=557)


1)执行AOF重写请求。 如果当前进程正在执行AOF重写,请求不执行并返回如下响应: ERR Background append only file rewriting already in progress 如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再 执 行,返回如下响应: Background append only file rewriting scheduled

2)父进程执行fork创建子进程,开销等同于bgsave过程。

3.1)主进程fork操作完成后,继续响应其他命令。所有修改命令依然写 入AOF缓冲区并根据appendfsync策略 同步到硬盘,保证原有AOF机制正确 性。

3.2)由于fork操作运用写时复制技术,子进程只能共享fork操作时的内 存数据。由于父进程依然响应命令, Redis使用“AOF重写缓冲区”保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。

4)子进程根据内存快照,按照命令合并规则写入到新的AOF文件。每 次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为 32MB,防止单次刷盘数据过多造成硬盘阻塞。

5.1)新AOF文件写入完成后,子进程发送信号给父进程,父进程更新 统计信息,具体见info persistence下的aof_*相关统计。

5.2)父进程把AOF重写缓冲区的数据写入到新的AOF文件。

5.3)使用新AOF文件替换老文件,完成AOF重写。


2.2.4 AOF 的优缺点

AOF的优点
  • 通过配置可以达到 实时持久化/秒级持久化 (会受限于磁盘性能)
  • AOF文件写入的都是文本命令,可以手动修改,可读性强,人工可干预。

AOF的缺点
  • AOF文件的体积要比RDB文件大
  • 虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。但在 Redis 的负载较高时,RDB 比 AOF 具好更好的性能保证

2.3 RDB-AOF混合


这里补充一个知识点,在Redis4.0之后,又新增了RDB-AOF混合持久化方式。


这种方式结合了RDB和AOF的优点,既能快速加载又能避免丢失过多的数据。
具体配置为:
aof-use-rdb-preamble


设置为yes表示开启,设置为no表示禁用。


当开启混合持久化时,主进程先fork出子进程将现有内存副本全量以RDB方式写入aof文件中,然后将缓冲区中的增量命令以AOF方式写入aof文件中,保证持久化的实时性,写入完成后通知主进程更新相关信息,并将新的含有 RDB和AOF两种格式的aof文件替换旧的aof文件。


简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。


这种方式优点我们很好理解,缺点就是不能兼容Redis4.0之前版本的备份文件了。

2.3 启动加载流程


![image.png](https://img-blog.csdnimg.cn/img_convert/8bde3069ecdafacd40e82d47a756a32e.png#align=left&display=inline&height=546&margin=[object Object]&name=image.png&originHeight=728&originWidth=703&size=152431&status=done&style=none&width=527)

总结

  1. Redis提供了两种持久化方式:RDB``和``AOF
  2. RDB使用一次性生成内存快照的方式,产生的文件紧凑压缩比更高,因此读取RDB恢复速度更快。由于每次生成RDB开销较大,无法做到实时持久化,一般用于数据冷备和复制传输
  3. save命令会阻塞主线程不建议使用,bgsave命令通过fork操作创建子进程生成RDB避免阻塞。
  4. AOF通过追加写命令到文件实现持久化,通过appendfsync参数可以控制实时``/``秒级持久化。因为需要不断追加写命令,所以AOF文件体积逐渐变大,需要定期执行重写操作来降低文件体积
  5. AOF重写可以通过auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数控制自动触发,也可以使用bgrewriteaof命令手动触发。
  6. 子进程执行期间使用copy-on-write机制与父进程共享内存,避免内存消耗翻倍。AOF重写期间还需要维护重写缓冲区,保存新的写入命令避免 数据丢失
  7. 持久化阻塞主线程场景有:fork阻塞和AOF追加阻塞。fork阻塞时间跟内存量和系统有关,AOF追加阻塞说明硬盘资源紧张。
  8. 单机下部署多个实例时,为了防止出现多个子进程执行重写操作,建议做隔离控制,避免CPU和IO资源竞争。

今天的你多努力一点,明天的C位就是你!

一起学习成为 C位程序员。💋
微信公众号已开启,【C位程序员】,没关注的同学们记得关注哦!
在这里插入图片描述

参考:《redis开发与运维》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值