图解redis的持久化存储机制 RDB和AOF

发布时间:2022-03-01 10:15:12 作者:yexindonglai@163.com 阅读(1035)

redis的持久化存储策略

redis是一个高性能的缓存数据库,既然是缓存,它的数据就是存储在内存中的,如果说服务器断电了, 或者重启了,或者redis宕机了,他的数据就一定会丢失,所以为了解决这个问题,在丢失数据之前就将数据给持久化保存到磁盘,这种持久化技术,就是RDB和AOF
在这里插入图片描述

什么是RDB

redis Database 的简写,是将redis内存中的数据保存为一个快照文件,类似Jmap的dump堆转储功能,但rdb是时点性的,只能存储某一时刻的快照,不能实时存储,如果单单使用rdb,它的数据就一定会丢失;
在这里插入图片描述

RDB优点

  1. 以快照的方式存储,所以恢复速度相对较快,
  2. 不支持拉链式的快照,也就是说,生成的快照文件永远只有一个;

RDB缺点

  1. 因为是时点性的,在持久化时将数据保存到磁盘需要一定的时间,在这段时间内可能会有其他的写操作,所以容易丢失数据

持久化触发方式

RDB的持久化触发方式有2种,分别为手动触发和自动触发,手动触发只需要登陆redis后输入相应的命令即刻,自动触发需要配置持久化的规则;

1、手动触发RDB

手动触发RDB持久化方式的命令有2种,分别是阻塞和异步:

  • save:执行save命令后redis进入阻塞状态,在RDB生成快照期间,redis不能执行其他命令,直到RDB完成方可解除阻塞状态;
  • bgsave:执行bgsave命令后,redis会以异步的方式进行持久化操作,以fork的方式创建一个子进程(注意是进程,不是线程);RDB持久化操作由子进程负责,完成后自动结束子进程;在异步持久化期间,redis可以正常执行命令;不会有任何影响;阻塞只发生在fork阶段,一般时间很短

注意事项

  1. 在命令行登录redis后输入save或者bgsave即可持久化存储;
  2. 基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令。
  3. 执行执行 flushall 命令,也会产生dump.rdb快照文件,但里面是空的.

2、自动触发RDB

先进入redis目录,打开redis.conf配置文件,找到以下几项配置:

  • rdbcompression yes :默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。
    • rdbchecksum yes:默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
  • dbfilename dump.rdb: 设置快照的文件名,默认是 dump.rdb
  • dir /usr/local/redis/rdb: 设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。

自动触发RDB的持久化条件

  • save "" :如果不想要使用RDB,可以使用此配置关闭 RDB功能
  • save 900 1: 900 秒内如果至少有 1 个 key 的值变化,则进行持久化保存
  • save 300 10: 300 秒内如果至少有 10 个 key 的值变化,则进行持久化保存
  • save 60 10000:60 秒内如果至少有 10000 个 key 的值变化,则进行持久化保存

bgsave底层原理

前置知识 - linux的fork函数、copy on write(流程图)

在了解异步RDB原理之前,我们需要先了解fork是个什么玩意;

调用fork函数后,linux会创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。

在克隆时,需要满足2个条件,

  1. 速度要快
  2. 占用内存空间要小

为了满足以上2点要求,linux使用了copy on write机制(写入时复制),也就是说,虽然是克隆了2一个子进程出来,但是父子进程种变量的内存指针还是指向同一个内存空间,比如一开始都父子进程的变量A的值都是123,但我修改子进程变量A的值时,改为456,那么操作系统会先在内存写入新的值456,然后在将子进程的变量A指向新的内存值456
在这里插入图片描述

克隆后的进程为子进程,常规情况下,子进程和主进程之间的数据完全隔离;互不影响;子进程的修改不会破坏父进程,父进程的修改也不会破坏子进程;

bgsave原理(流程图)

在输入bgsave命令后,redis在内部做了以下几件事

  1. 通过fork函数创建一个子进程;此方法会产生阻塞,但时间很短;
  2. redis的增删改查由父进程负责;
  3. 持久化RDB由子进程负责;
  4. 持久化完成后,子进程自动结束;
    在这里插入图片描述

AOF

append only file的简写,意思是只会向文件追加,指的是客户端对redis的增、删、改操作,会以追加的形式将操作语句保存到文件中;
在这里插入图片描述

AOF优点

  1. 恢复时丢失数据少
  2. RDB和AOF可同时开启;在4.0以前恢复时只用aof恢复;4.0以后使用混合型的持久化机制,下文会介绍

AOF缺点

  1. 速度较慢,每次写操作都会写磁盘;

rewrite机制(重写)

为什么需要rewrite

我们都知道磁盘空间是有限的,但是redis的增删改的命令却是无穷无尽的,为了保证磁盘不被占满,就需要引入rewrite机制;在命令行输入以下指令即可触发rewrite重写AOF文件;

  1. BGREWRITEAOF
rewrite原理

rewrite机制是自动触发的,需要设定一个阈值,也就是你的aof文件大小的阈值,比如我设置大小为64M时,当aof文件大小达到64M就会自动触发rewrite机制,会对aod文件做些优化,去掉一些过程重复的命令;比如我连续执行了下面的命令

  1. set name yexindong
  2. set name zhangsan
  3. set name lisi

那其实,name最终的结果是lisi,也就是第三个命令,第一个和第二个执不执行都不会影响最终的结果,所以当aof文件叨叨64M时,rewrite原理触发,就会将下面的语句删除

  1. set name yexindong
  2. set name zhangsan

最后只保留set name lisi的语句;去掉中间没用的语句,优化就完成了;经过这一次瘦身,aof文件就会变得更小了;
在这里插入图片描述

AOF使用

同样的,AOF也需要在配置文件中进行相关配置;

  • appendonly no: 默认值为no,也就是说redis 默认使用的是rdb方式持久化,如果想要开启 AOF 持久化方式,需要将 appendonly 修改为 yes。
  • appendfilename "appendonly.aof":AOF文件名称,配置后,就会将写指令追加到这个文件内

  • dir /usr/local/redis/rdb: AOF文件的保存目录,与RDB一致

  • 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对日志文件进行重写(rewrite)。当前AOF文件大小是上次日志重写得到AOF文件大小的二倍(设置为100)时,自动启动新的日志重写(rewrite)过程。
  • auto-aof-rewrite-min-size:64mb。设置允许重写(rewrite)的最小aof文件大小,避免了达到约定百分比但尺寸仍然很小的情况还要重写(rewrite)。

  • aof-load-truncated:aof文件可能在尾部是不完整的,当redis启动的时候,aof文件的数据被载入内存。重启可能发生在redis所在的主机操作系统宕机后,尤其在ext4文件系统没有加上data=ordered选项,出现这种现象 redis宕机或者异常终止不会造成尾部不完整现象,可以选择让redis退出,或者导入尽可能多的数据。如果选择的是yes,当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。如果是no,用户必须手动redis-check-aof修复AOF文件才可以。默认值为 yes。

aof使用注意事项

要使用AOF功能,在启动时不能直接运行redis-server。一定要加配置文件运行./redis-server /etc/redis/redis.conf,加了配置文件后AOF功能才会生效

AOF文件内容说明

首先我们执行下面这个命令,看看aof文件中都保存了哪些东西;

  1. set k1 hello

然后通过命令打开aof文件 vim appendonly.aof,可以看到以下内容

  1. *2 // *开头表示是一个新命令,这个命令有2个元素组成
  2. $6 // $开头表示下一行命令的字符长度
  3. SELECT // 选择库的指令,redis有16个库:0~15之间
  4. $1
  5. 0 // 和上面的命令组成为:SELECT 0,表示选择0号库
  6. *3 // 下一个命令,这个命令有3个元素组成
  7. $3 // 下一行的命令长度
  8. set // set命令
  9. $2
  10. k1 // key 的名称
  11. $5
  12. hello // key的值,和上面2个命令组成:set k1 hello

Redis是如何进行持久化的(流程图)

在reids4.0的以后,提供了一种混合型的持久化机制,就是RDB + AOF的持久化方式;在配置文件中会有以下配置,设置为yes表示开启,设置为no表示禁用。默认为yes

  1. aof-use-rdb-preamble yes

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

也就是说,RDB 和 AOF文件是在同一个文件里面的,在进行备份的时候,比如是2点整进行备份的,先将这个文件先删除掉,然后将当前的数据以RDB快照的方式保存到aof文件种,最后,以增量的方式将增、删、改命令追加到AOF文件中;这样就可以保证重启或者断电后,恢复数据会保持和断电前一致了;
在这里插入图片描述

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

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

数据恢复

启动redis时,redis会自动加载rbd文件和 aof文件进行数据恢复;前提是得先开启相应的配置后才会恢复数据,配置如下

  1. # 开启 AOF 持久化配置
  2. appendonly yes
  3. # 开启 RDB持久化配置
  4. rdbcompression yes

关键字Redis