Redis持久化中RDB和AOF有哪些区别?你知道吗!

举报
Java小叮当 发表于 2022/03/30 23:40:47 2022/03/30
【摘要】 前言 关于Redis的知识点总结了一个思维导图分享给大家 Redis是一个内存数据库,为了保证数据不丢失,必须把数据保存到磁盘,这就叫做持久化。 Redis有两种持久化方法:RDB方式以及AOF...

前言

关于Redis的知识点总结了一个思维导图分享给大家

Redis是一个内存数据库,为了保证数据不丢失,必须把数据保存到磁盘,这就叫做持久化。

Redis有两种持久化方法:RDB方式以及AOF方式。

RDB持久化

RDB持久化把内存中的数据持久化到硬盘,生成RDB文件,也就是“快照”。通过RDB文件可以重新恢复内存中的数据。RDB文件是一个压缩过的文件,因此RDB持久化的体积比AOF小,因为存储的是数据,所以恢复很快,性能好,但是可能会丢失最后一次持久化的数据。

RDB持久化机制的两种方式

显示开启持久化

Save命令

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

BGSAVE命令

BGSAVE命令会fork一个子进程,由子进程负责创建RDB文件,父进程继续处理命令请求

1.子进程执行BGSAVE命令期间,SAVE/BGSAVE命令会被父进程拒绝。因为Redis不允许两个进程同时进行持久化

2.BGSAVE和BGREWRITEAOF命令同样不能同时执行,性能考虑

自动持久化机制

通过配置文件redis.conf

#多久持久化一次🐲🐲
#900秒内有一个key改动 300秒内1060秒内10000个
save 900 1
save 300 10
save 60 10000

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

底层实现:

1.Redis服务器的周期性操作函数serverCron默认每100ms执行一次,该函数用户对正在执行的服务器进行维护,它的其中一项工作就是检查save选项所设置的持久化条件是否满足,满足的话执行BGSAVE命令

2.Redis使用saveparams数组保存持久化条件

dirty计数器和lastsave记录上一次持久化到现在修改了几次和上一次执行SAVE或者BGSAVE的时间戳

RDB文件的结构

参考《REDIS设计与实现》P125

后续补充,先说一下目前总结,其实也就是databases的结构:

redis有多个数据库,如果每个数据库都为空,那么databases也为空。如果不是的话,database的结构差不多是这样的:

key_value_pairs部分保存了该数据库中所有的键值对数据,如果键值对带有过期时间,过期时间也会和键值对保存在一起。会根据value的不同类型采用不同的结构存储

接下来看一个完整的RDB文件结构示例,包含0号数据库和3号数据库

key_value_pairs 字段详解~)

分析RDB文件

使用od-c dump.rdb命令根据rdb文件的结构人工分析,或者使用工具redis-dump-check分析。分析RDB文件其实没有实际的意义,但可以帮助我们进一步理解RDB文件的结构。

AOF持久化

引言

AOF持久化与RDB持久化不同,RDB持久化把内存中的数据按照某种格式存储到硬盘中,而AOF持久化是把所有写命令记录到硬盘,恢复的时候需要重新执行所有写命令。

在这个AOF文件里面,除了用于指定数据库的SELECT命令是服务器自动添加的之外,其他都是我们之前通过客户端发送的命令。

AOF持久化的实现机制

AOF持久化的实现有三步:

1.命令追加:每执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器内核的aof_buf缓冲区的末尾

2.命令写入:操作系统调用write函数,将aof_buf缓冲区的数据排入队列,晚些时候一起写入磁盘

3.命令同步:操作系统调用fsync和fdatasync 两个同步函数,强制让操作系统立即把队列中的数据写入磁盘

总的来说其实就是每执行完一次写命令(也叫做一个事件循环),redis都会把这条命令格式化后写到缓冲区,再从缓冲区持久化到磁盘。但是你可能会有疑问,这不是两步吗,为什么 write 函数不能直接把缓冲区的数据同步到磁盘,这就涉及Linux内核关于文件IO的知识了,这里简单解释一下。

为了提高文件的写入效率,在现代操作系中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区(队列)里面,
等到队列的空间被填满、或者超过了指定的时限之后,才真正地将队列中的数据写入到磁盘里面。这种方式又叫做延迟写。

如何开启和配置AOF持久化

同样是配置redis.conf文件

#是否开启aof持久化🐲🐲
appendonly no

#aof持久化文件名
appendfilename "appendonly.aof"

#aof持久化策略 默认是一秒持久化一次🐲🐲
#appendfsync always
appendfsync everysec
#appendfsync no

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

上述的持久化策略就是配置命令同步 的时机。

1.no:只有等队列满了数据才会持久化到磁盘。如果此时服务器宕机了,可能会丢失上次同步之后的所有命令数据。效率最高。

2.always:每写入一条命令就要同步一次,安全性最高,最多丢失一条命令的数据。但是效率最低。

3.everysec:每一秒钟执行同步一次,最多丢失一秒的数据。

如何载入AOF文件还原数据

也就是如何通过AOF文件还原数据库的过程

1.创建一个不带网络连接的伪客户端。因此redis命令只能在客户端的上下文执行

2.从AOF文件中分析一条写命令

3.客户端执行命令,循环2 3过程

AOF重写机制

引言

随着服务器运行时间的流逝,可能会频繁的对同一个key进行很多写操作,AOF文件中的内容会越来越多,文件越来越大,如果不加以控制,会对服务器造成影响,还原数据的时间也加长。

比如现在有一个键值对为list类型,在服务器运行时间,你对这个key进行了十次写操作。AOF在持久化时就要保存十条命令,但是我们只保存一条命令也可以还原此key的状态。

重写机制就是这样实现的:Redis服务器创建一个新的AOF文件替代现有的AOF文件,新旧两个文件保存的数据库状态相同,但是新的AOF文件不会包含浪费空间的冗余命令,只保存必须的命令,因此新的AOF体积就要小得多。

触发方式

1.手动触发

使用BGREWRITEAO命令,fork子进程重写aof

2.自动触发,配置redis.conf

#重写aof文件的配置🐲🐲
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

  
 
  • 1
  • 2
  • 3

实现机制

通过读取服务器当前数据库状态来实现的,不依赖旧的AOF文件。

如果服务器想要用最小的命令来记录key的状态,最简单高效的方法就是读取key的值,记录一条插入(add、push …)的命令。一条就完事,不用在意以前的写命令是什么。

因为AOF重写会进行大量的写入操作,因此Redis使用单个子进程来处理命令请求实现AOF重写,缩小AOF文件体积。

为什么是进程不是线程呢?

1.子进程重写期间,服务器父进程可以继续处理命令请求

2.子进程有服务器进程的数据副本,不会导致线程安全问题

总结

Redis持久化有RDB持久化和AOF持久化两种,RDB效率高但是可能会丢失大量数据,安全性较低,AOF效率低但是安全性高。

Redis默认使用的持久化方式是RDB持久化

AOF重写的目的是为了减小aof文件的体积

最后

我这边整理了一份:Redis相关面试资料、Java的系统化资料,(包括Java核心知识点、面试专题和20年最新的互联网真题、电子书等)有需要的朋友可以关注公众号【程序媛小琬】即可获取

文章来源: blog.csdn.net,作者:Java小叮当,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/m0_48795607/article/details/116895419

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。