Redis学习笔记:持久化

这是本人学习的总结,主要学习资料如下

  • B站狂神说,redis教程
  • 马士兵


1、RDB持久化和AOF持久化概述

这两个是redis的持久化策略。

所谓的持久化,就是redis为了防止内存中的数据丢失,于是将当前内存的数据用各种形式存储到内存中,这样就能从意外停机中恢复数据。

RDB是Redis Data Base的缩写,AOF是Append Only File的缩写。

RDB模式保存的文件默认是dump.rdb,而AOF则是dump.aof


2、RDB持久化

2.1、RDB持久化策略

RDB的持久化策略如下图所示。

在这里插入图片描述

主进程用来处理redis的指令,同时会有一个子进程专门用来处理持久化操作。

redis数据发生改变时,主进程将数据写入常规的内存数据库时,也会用os写时复制机制将改变的情况写入共享内存中。

子进程到共享内存中读取变化的数据,然后写入临时文件。临时文件过一段时间后会将变更信息写入正式文件。

整个过程主进程不会产生IO操作,这样即使持久化时发生错误,也能保证服务正常运行。



2.2、RDB特性

  • 不影响redis服务:因为会有子进程专门负责持久化工作,即使持久化工作出错也不会影响主进程。需要注意,子进程的工作确实不会阻塞主进程,但是主进程需要fork出子进程去完成持久化操作。这个fork是会阻塞主进程的。所以我们也不能频繁地去进行RDB持久化。
  • 较高的性能:如上所述,主进程可以安心处理自己的工作,所以服务会更稳定,性能较高。
  • 不保证完全持久化:因为持久化错误后不影响redis的服务,所以redis的变更可能不是很完整。

2.3、启动RDB持久化的方式

2.3.1、手动执行命令

  • bgsave:创建子线程去执行RDB快照,主线程不受影响。
    可以看到bgsave执行后显示后台开始持久化=.
127.0.0.1:6379> bgsave
Background saving started

  • save: 立即开始RDB持久化。
127.0.0.1:6379>save
ok

2.3.2、通过配置定时自动持久化

有关RDB持久化的配置项是save withinSeconds num。其中save是关键字,withinSecondsnum都是整数。

withinSeconds表示时间,单位是秒。num表示写操作的次数。这个命令的含义就是如果在withinSeconds秒内发生num次写操作,那就执行一次RDB持久化。

比如save 300 10表示,如果在300s内发生10次写操作,那就执行一次RDB持久化。

那么常规来说,修改配置就两种方式,一个是通过config set key value修改配置后,使用save保存即可。

127.0.0.1:6379> config set save "10 10"
OK
127.0.0.1:6379> save
OK
127.0.0.1:6379> config get save
1) "save"
2) "10 10"

另一种是在redis.conf中修改,重启redis即生效。以下是默认配置

# save 900 1
# save 300 10
# save 60 10000

需要注意的是,在配置文件中可以设置多个条件的save。设置多个的话,只要满足其中任意一条,那redis就会启动一次RDB持久化


2.3.3、关闭服务时自动保存

当我们使用shutdown关闭redis时,redis也会触发一次RDB持久化。

下面是我执行shutdown后redis的日志,我们可以看到它在22:15:44时完成DB saved on disk

56416:M 01 Feb 2023 21:29:22.914 * Background saving terminated with success
56416:M 01 Feb 2023 22:02:24.966 * DB saved on disk
56416:M 01 Feb 2023 22:15:44.830 # User requested shutdown...
56416:M 01 Feb 2023 22:15:44.830 * Saving the final RDB snapshot before exiting.
56416:M 01 Feb 2023 22:15:44.831 * DB saved on disk
56416:M 01 Feb 2023 22:15:44.831 # Redis is now ready to exit, bye bye...

我们查看对应的dump.rdb文件,修改时间也是22:15:44
在这里插入图片描述


2.4、RDB数据丢失问题

这很容易想到,因为RDB的持久化不是每次操作都会去持久化,所以如果在下一次持久化前发生宕机,那这中间的数据就会丢失。

下图就是T1时刻发生写入操作,但持久化没开始前就发生宕机,于是修复后的数据缺失了T1时刻的内容。
在这里插入图片描述




3、AOF持久化

3.1、AOF持久化策略

AOF也会生成一个名为appendonly.aof的文件存储数据。但是与RDB方式不同的是,这份文件会顺序存储写入的指令。当需要恢复数据时,就可以顺序执行这些指令达到恢复数据的目的。

AOF持久化逻辑是这样的:当redis接收到一条写命令时,会将该指令存放在一个缓存内存中,我们称为AOF缓冲,如下图所示。等满足一些条件时(这些条件和配置appendfsync有关,具体可以继续往下看),这些写入指令会写入appendonly.aof文件的末尾。

在这里插入图片描述



3.1.1、指令写入文件的时机

我们可以选择想要的方案,选择缓存中的指令存进appendonly.aof文件末尾的时间点。只需要设置配置文件中appendfsync属性即可。

  • appendfsync always:只要接收到一条写入指令,就立刻存进appendonly.aof文件中。很明显,这样确实安全性很高,完全可以保证数据不丢失,但是频繁的IO操作会大大降低redis的性能,减少磁盘的寿命。
  • appendfsync no:不同步数据,相当于关闭了AOF。
  • appendfsync everysec:这算是第一种和第二种策略的折中,对写入的时机有控制,但不是控制很频繁。该策略是每过一秒就将指令写入appendonly.aof文件中。

3.2、AOF重写

经过一定时间的运行后,appendonly.aof文件肯定会越来越大。同时文件中有些命令是无效的,比如set k1 v1set k1 v2, set k1 v3,我们只需要存最后一条语句就行了。为了缩减appendonly.aof文件的大小,redis就会执行AOF重写策略。




3.2.1、重写策略

  1. 父进程创建一个子进程,子进程负责将当前内存中的redis数据转化成写指令并将这些指令存进临时的appendonly.aof文件中。注意,该文件和旧的appendonly.aof不是同一个,目前两者是同时存在的。
  2. 在子进程完成工作之前,若redis又接收到了新的写指令,父进程会将这些指令存进临时的指令缓存空间,同时也将这些指令写入旧的appendonly.aof文件中。这样即使在此期间系统发生故障,redis也能保证这段时间改变的数据及时存到旧的appendonly.aof文件中。
  3. 等子进程完成工作后,会给父进程发送一个信号。父进程收到信号后会将第二步中提到的临时指令缓存空间中的指令追加到子进程创建的appendonly.aof文件中。
  4. 之后子进程创建的这个新appendonly.aof文件会替代旧的appendonly.aof文件,完成重写。

在这里插入图片描述


3.2.2、AOF重写的时间

3.2.2.1、指令

通过指令主动重写:bgrewriteaof

127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started

3.2.2.2、配置

有两个配置可以决定AOF重写的时机,这两个配置是一起使用的。

  • 动态大小重写:auto-aof-rewrite-percentage percentage,从上次AOF结束开始计算,这段时间内如果AOF新增加的大小达到了上次AOF时appendonly.aof的某个百分比,那就再执行一次AOF。
    auto-aof-rewrite-percentage是关键字。
    percentage是整数,表示百分比。
    比如下面的命令是当新增加的内容大小超过上次AOF appendonly.aof大小的50%则进行一次AOF。比如上次AOF时appendonly.aof是50MB,当AOF缓冲区的大小达到25MB时就进行一次AOF。
auto-aof-rewrite-percentage 50

  • 最低重写大小:auto-aof-rewrite-min-size size,对上一个配置的限制。上一个配置根据appenonly.aof的大小百分比来决定是否AOF。这个配置的意思是除了AOF缓冲区达到上次AOF时appenonly.aof的某个百分比以外,appenonly.aof的大小还得超过size才进行重写。
    auto-aof-rewrite-min-size是关键字。
    size是整数,需要自己写单位,比如64mb。表示AOF缓冲区要超过size后才能进行AOF重写。
    比如下面的命令是当AOF缓冲区超过上次AOF appendonly.aof大小的50%,并且AOF缓冲区超过64mb时,则进行一次AOF。比如上次AOF时appendonly.aof是50MB,当AOF缓冲区的大小超过25MB并且超过最低限制64MB时进行AOF,所以AOF缓冲区到达64MB时会进行一次AOF重写。
auto-aof-rewrite-percentage 50
auto-aof-rewrite-min-size 64mb

3.3、开启和关闭AOF持久化

相关的配置是appendonly。如果开启则是appendonly yes,关闭则是appendonly no

3.4、修复被损坏备份文件

修复错误:redis-check-aof --fix,自动修复。



3.5、Redis的重启恢复数据流程

流程图如下所示,简单一句话,有AOF就用AOF恢复数据,没有AOF才用RDB。

请添加图片描述


4、RDB和AOF混合保存数据

使用RDB时,数据有丢失的风险,因为两次RDB的间隔时间可能会比较长;

使用AOF的缺点是,redis经过一段时间后,appendonly.aof会变得比较大。恢复数据时一条条执行指令可能会花较长的时间;

而RDB是存储快照,是二进制文件,空间小。且回复数据时基本上直接复制这个文件内容到内存中即可,速度远远快于AOF。

为了取长补短就有了两者的混合模式。

4.1、配置

  • aof-use-rob-preamble yes
    aof-use-rob-preamble是关键字。
    yes,开启混合模式则是yes,不开启是no

4.2、流程

在混合模式下,redis正常还是用AOF的方式记录数据。和AOF不同的是,混合模式保存的appendonly.aof的格式。

混合模式中appendonly.aof被分为两个部分,前面是RDB的快照,后面是AOF的指令数据。

需要恢复数据时redis就可以通过保存的redis快照快速回复数据。

当然AOF持久化会每秒进行一次,这里持久化的内容只有指令,没有RDB的内容,和一般的AOF一样。

RDB的数据备份只有AOF重写发生时才会有一次。

流程如下。
请添加图片描述



5、常见问题

  • 主线程,子线程和后台线程的区别
    redis中,主线程主要就是负责和外界的读写,剩下的一小部分工作则是交给子线程和后台线程去完成。当然生成子线程或者调用后台线程也会调用主线程的一小部分时间。

    子线程由主线程fork生成,这个操作会让主线程短暂阻塞。子线程占用的空间都是属于主线程的,两者之间的数据是共享的,一般用来完成RDB和AOF的相关操作。
    之所以用子线程去做持久化而不是用后台线程,是因为持久化过程中需要访问主线程存的数据,将这些数据从内存复制到硬盘中。主线程不和后台线程共享数据所以持久化不能用后台线程完成。

    后台线程是用来服务主线程的,他不属于主线程,他不占用主线程的空间。一般后台线程用来完成一些异步的操作,比如redis关闭后的一些后续操作。

请添加图片描述


  • Redis持久化过程中有没有其它的阻塞风险?
    当然有。前面提到过,尽管持久化工作都是由子线程完成,但是fork出子线程是会令主线程短暂阻塞的。所以频繁持久化会导致主线程阻塞。

  • 为什么主从复制不用AOF文件复制
    appendonly.aof是文本文件,是一堆字符串。使用这个文件复制数据需要一条条执行里面的指令,执行还涉及到语义分析,编译等过程,时间开销大。

    RDB文件是二进制文件,占用空间小,几乎可以看成内存中的内容直接复制到硬盘中。用这个文件复制数据只需要将该文件复制到内存中即可,时间快很多。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值