【Redis学习】持久化机制(RDB/AOF)

Redis学习:

https://blog.youkuaiyun.com/2301_80220607/category_13051025.html?spm=1001.2014.3001.5482

目录

1. 认识持久化

2. RDB机制

2.1 触发机制

2.2 bgsave命令的流程说明

3. RDB文件

4. RDB效果演示

4.1 手动触发

4.2 自动触发

4.3 RDB文件的检测

5. RDB机制总结

6. AOF机制

7. AOF的基本使用

8. AOF 的效率和同步问题

8.1 AOF 的效率问题

8.2 AOF 的同步问题

9. AOF 的重写机制

10. 启动时数据恢复

11. 总结


1. 认识持久化

学习过mysql的都知道,mysql事务有四个非常重要的特性:原子性、一致性、持久性、隔离性。这里的持久性就是我们这里要说的持久化了,那么MySQL是如何做到数据的持久性的呢?方法就是将数据存储到磁盘中去,那么redis能否这样做呢?

我们前面一直在说,Redis之所以能够做到快速的对数据进行操作,原因就是它是将数据存储在内存中的,如果我们将数据存储到磁盘上,那么Redis不就会丧失它的特性了嘛。但并不意味着我们的Redis就无法进行持久化操作了,我们采取的方法是:在内存和磁盘上各存储一份。

磁盘上的那份只负责:当我们打开Redis时,对我们之前的数据进行恢复;平时的使用还是直接在内存中进行。这样的缺点就是消耗的空间变多了,因为我们相当于要写入两份数据(内存和磁盘),但总体来说还是问题不大的,因为磁盘价格很低

Redis支持RDB (Redis DateBase) 和AOF (Append Only File) 两种持久化机制,具体到方法上来说就是支持定期备份和实时备份两种方法。

2. RDB机制

RDB机制就是按照定期备份的方法来对我们的数据进行持久化的。Redis定期的把内存中的数据全部写入磁盘中,生成一个快照,后续重启Redis的时候,虽然我们内存中的数据已经没了,但是我们可以通过磁盘中的快照文件恢复原来的数据

2.1 触发机制

定期备份的触发方式有两种:手动触发和自动触发

手动触发分别对应save和bgsave命令

  • save命令:阻塞当前进程,直到RDB过程完成为止,对于内存比较大的实例是比较灾难的,因为Redis是单线程的,所以我们一般不使用这个命令
  • bgsave命令:Redis进程执行fork创建子进程,子进程来完成Redis的持久化工作,完成后自动结束。这种方法阻塞只发生在fork阶段,时间比较短

除了手动触发外,Redis运行自动触发Redis备份机制,这种机制在实战中更有意义

  • 使用save配置:如“save m n”表示m秒内,数据集发生了n次修改,就自动RDB持久化
  • 从节点进行全量复制操作时,主节点自动进行RDB持久化,随后将RDB文件内容发送给从节点
  • 执行shutdown命令关闭Redis时,执行RDB持久化

2.2 bgsave命令的流程说明

  1. 执行bgsave命令,Redis判断现在是否有正在执行的子进程,比如RDB/AOF子进程,如果有,bgsave直接退出
  2. ⽗进程执⾏ fork 创建⼦进程,fork 过程中⽗进程会阻塞,通过 info stats 命令查看
    latest_fork_usec 选项,可以获取最近⼀次 fork 操作的耗时,单位为微秒。
  3. ⽗进程 fork 完成后,bgsave 命令返回 "Background saving started" 信息并不再阻塞⽗进程,可以继续响应其他命令。
  4. ⼦进程创建 RDB ⽂件,根据⽗进程内存⽣成临时快照⽂件,完成后对原有⽂件进⾏原⼦替换。执 ⾏ lastsave 命令可以获取最后⼀次⽣成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选 项。
  5. 进程发送信号给⽗进程表⽰完成,⽗进程更新统计信息。

3. RDB文件

查看:

首先我们先来看一下我们如何找到RDB文件并进行查看,我们可以先看一下我们Redis的配置文件redis.conf,在/etc/redis这个目录下

我们使用vim进入这个配置文件后,可以查看我们的工作目录为/var/lib/redis

我们的RDB文件就存在于这个工作目录之下:

这个文件我们可以使用vim进行查看,但里面由于是二进制压缩过的,所以我们可以看到里面是乱码。

切记不要手动修改dump.rdb文件中的内容,修改了可能会导致我们的redis无法正确启动

检验:

如果你不小心对dump.rdb文件中的内容做出了修改,或者由于某些原因Redis加载dump.rdb文件时失败了而拒绝启动。这时可以使用Redis提供的redis-check-dump工具检测RDB文件并获取对应的检测报告


我们的Redis是按照一定的规则定期生成RDB文件的,那么具体的生成规则是什么呢?

当执行生成RDB镜像时,我们把要写的快照信息先写入一个临时文件,当这个快照生成完毕之后,我们把原来的RDB文件删除,然后将这个临时文件改名为dump.rdb,所以说RDB文件自始至终只能有一个

4. RDB效果演示

4.1 手动触发

我们同时打开多个终端,一个打开redis进行操作,另一个可以查看dump.rdb文件观察数据的持久化情况

我们可以看到此时我们的redis中是没有数据的,如果此时我们向我们的redis中插入几个值,我们的dump.rdb文件会有变化吗?

插入后我们会发现我们的RDB文件中的内容并没有发生变化,原因是什么呢?其实就是我们前面所说的,RDB机制并不是实时备份的,需要我们手动触发或者满足一定的条件后自动触发

手动触发的方式我们上面讲了是有save和bgsave两种命令:

下面我们看一下具体如何操作

如图我们又添加了两个新的值key3和key4,然后我们使用bgsave手动触发RDB机制,然后此时查看我们的RDB文件,通过一些关键字我们就可以看到我们的值已经被备份到RDB文件中了,此时如果我们重启了redis服务器,RDB文件就会被加载恢复内存之前的状态

在手动触发查看RDB文件时,有一个需要注意的小细节是:这里我们新写入的数据很少,所以手动触发后直接查看RDB文件就可以发现新写的数据已经进行了备份,但是如果我们写入的数据很多,此时再使用bgsave手动触发的时候,子进程就需要更多的时间在后台完成备份,此时我们短时间内就去查看我们的RDB文件可能就会因为还没备份完而看不到新写入的数据

这里我们再讲解一下save和bgsave的区别:

我们上面提到save和bgsave最大的不同就是一个是阻塞当前进程进行备份的,一个是创建子进程进行备份的,那么具体是如何工作的呢?我们可以结合实例看一下

由于我们数据过少的原因,bgsave创建子进程后,子进程的持久化过程是非常快的,所以我们很难通过观察进程的方式来看我们是否创建了一个子进程,但是我们上面还提到的一个东西就是:子进程会将生成的快照先写入一个临时文件中,全部备份完之后会将原RDB文件删除,然后将新生成的文件改名成dump.rdb,所以我们可以通过观察RDB文件inode的方法,来查看bgsave之后是否生成了新的文件,从而来判断我们bgsave是否手动触发成功(save命令是阻塞当前进程,然后将快照直接写入原RDB文件中的,不会生成新的RDB文件)

我们可以使用stat filename命令查看文件的inode

起初RDB文件的inode:

bgsave命令执行后:

我们可以发现RDB文件的inode发生了变化,也就是说这个RDB文件并不是原来的RDB文件了,这就侧面说明我们的bgsave正确完成了备份工作(临时文件+重命名机制)

4.2 自动触发

RDB机制也可以自动触发

我们先来看这样一个现象,当我们往Redis中写入几个值的时候,此时我们如果直接退出Redis(注意要使用ctrl+c,不要使用quit),我们会发现我们刚刚写入的值并没有成功备份,但是如果此时我们重启Redis服务器后(systemctl restat redis-server),再查看dump.rdb文件就会发现已经备份了

这就可以验证我们上面所说的一种自动触发的情况:执行shutdown命令关闭Redis时,执行RDB持久化(正确关闭重启Redis服务器时,也会自动触发)

但是如果我们不是正确退出服务器,而是异常重启(kill -9 或者 服务器断电),此时Redis服务器就会来不及生成 rdb,内存中尚未保存到快照中的数据,就会随着服务器的重启而丢失

如图1,我们 ctrl+c 退出redis后,然后杀死redis服务器,我们会发现redis服务器很快就会自动重启,这是因为Redis是作为系统服务安装的,它被配置为系统服务,由系统的进程管理器(如systemd 或 init)监控和管理。当Redis进程异常退出时,进程管理器会自动重启它。

按照我们上面讲的,异常退出后我们之前插入的数据并没有生成快照保存到RDB文件中,从图二也可以看出我们的RDB文件中并没有 key1 key2,那么为什么我们的redis进程自动重启后,我们进入查看仍能看到之前的数据呢?这实际上是另一种持久化机制---AOF 在发力,下面会讲解


除了这种自动触发方式外,我们上面还提到有两种触发方式:从节点全量复制的时候和满足配置文件配置选项的时候

从节点全量复制也属于一个比较大的话题,后面会讲,现在我们来看一下配置文件这种情况

我们可以查看redis的配置文件(路径:/etc/redis/redis.conf)

里面有这几项内容,最上面的注释语句就是告诉我们 save 配置的规则是:save m n,意思是在m秒内修改n次就会自动触发RDB,最下面的三条就是我们的默认的 save 配置,save " " 的意思是不启用 save 配置(关闭自动生成快照)

4.3 RDB文件的检测

在上面的时候我们就讲到,当我们的 rdb 文件发生损坏的时候,我们的 redis 服务器可能就会无法正常启动,下面我们来故意修改一下 rdb 文件来看一下具体会出什么错误,以及我们如何检测我们出现的错误

我们手动的删除 rdb 文件中间的一些内容,然后再重新启动一下服务器(注意要用 kill -9 的方式启动服务器,因为如果我们使用 systemctl restart redis-server ,会自动触发RDB,然后生成新的RDB 文件)

(注意上面的操作是在关闭了aof机制下进行的,aof机制不关闭的话可能无法观察到这种情况

此时 redis 服务器无法工作的时候,我们可以看看 redis 日志,了解一下发生了什么

redis 日志文件所在的路径为:/var/log/redis(这个路径也是在配置文件中配置的)

我们的RDB文件的修改是在最近一次操作的,所以直接查看最后一条日志就是了,这条日志就告诉我们在 rdb 数据恢复中出现了错误

除了查看日志外,我们也可以通过 redis 提供的检测工具来检查我们的 RDB 文件是否有错误

我们使用这个检测工具也非常简单,在这个命令后加上文件名即可

注意要在RDB文件的工作目录下执行这个检测语句才行,执行后我们也可以看到我们的 RDB 文件是有错误的

观看到之后修复 RDB 文件也很简单,正确重启一次即可(systemctl restart redis-server)

5. RDB机制总结

  • RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景,比如每6个小时执行bgsave备份,并把 RDB 文件复制到远程机器或者文件系统中(如 hdfs)用于灾备。
  • Redis 加载 RDB 恢复数据远远快于 AOF 的方式,原因:RDB 使用的二进制的方式来组织数据,直接把数据读取到内存中,按照字节的格式取出来,放到结构体/对象中即可;而 AOF 是使用文本的方式来组织数据的,需要进行一系列的字符串切分操作。
  • RDB 方式数据没办法做到实时持久化/秒级持久化。因为 bgsave 每次运行都要执行 fork 创建子进程,属于重量级操作,频繁执行成本过高。
  • RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个 RDB 版本,兼容可能有风险。老版本的 redis 的 RDB 文件放到新版本的 redis 中不一定能识别,如果遇到要升级版本,且遇到了不兼容的问题,可以通过写一个程序的方式,直接遍历旧的 redis 中的所有key,把数据取出来之后,插入到新的 redis 服务器中即可。

6. AOF机制

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

7. AOF的基本使用

AOF 机制有点类似于 mysql 的 binlog,会把用户的所有操作都记录下来写入文件中。当Redis重启的时候就可以读 aof 文件中的内容恢复数据。

AOF 默认是关闭的,如果要开启需要修改配置文件,而且 AOF 开启后,RDB 就会失效。

修改后重启服务器就奏效了

图片中下面这个就是我们的 aof 文件的文件名,这个文件与 RDB 文件是存放在同一个目录下的(/var/lib/redis)

AOF 是一个文本文件,每次进行的操作都会被记录到文本文件中,通过一些特定的符号来对文件进行分割,要知道分割也是按照一定规则的,具体的分割规则我们这里就不做讲解了

8. AOF 的效率和同步问题

8.1 AOF 的效率问题

我们都知道 Redis 之所以操作起来速度比较快的原因,就是因为它是对内存进行操作的,现在我们的 AOF 要求我们同时往内存和硬盘上写数据,那么工作效率还能得到保障吗?

答案是:没有影响!!原因是:

  1. AOF 机制并非直接让工作线程把数据写入到磁盘当中,而是先写入一个内存缓冲区中的,当缓冲区满了再刷新到磁盘中去,硬件交互的工作是最耗时的,这样减少了访问硬件的次数就提高了效率
  2. 磁盘顺序读写的速度要明显快于随机访问,AOF 机制每次把最新的操作都写入到文件末尾,属于顺序写入

8.2 AOF 的同步问题

当然,这种先写入内存缓冲区的方法也不全是好处,这样说到底还是先写在内存中的,此时如果我们的机器出现了问题,比如断电等情况就会让我们的服务异常退出,那么我们内存缓冲区中的数据就会还没来得及刷新到磁盘中就丢失,我们使用 AOF 机制想实现的实时更新的目的就没能达到

所以基于上面所讲,我们就可以得出缓冲区的刷新策略:

  • 刷新频率越高,性能影响就越大,但是数据可靠性就更高
  • 刷新频率越低,性能影响就越小,但是数据可靠性就更低

Redis 提供了多种 AOF 缓冲区文件同步策略,由参数appendfsync控制,有多种可配置选项

可配置值
说明
always
命令写⼊ aof_buf 后调⽤ fsync 同步,完成后返回
everysec
命令写⼊aof_buf 后只执⾏ write 操作,不进⾏
fsync。每秒由同步线程进⾏ fsync。
no
命令写⼊ aof_buf 后只执⾏ write 操作,由 OS 控制
fsync 频率。

一般选择的第二个配置项

系统调用 write 和 fsync 说明:

  • write 操作会触发延迟写(delayed write)机制。Linux 在内核提供⻚缓冲区⽤来提供硬盘 IO 性能。write 操作在写⼊系统缓冲区后⽴即返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区⻚空间写满或达到特定时间周期。同步⽂件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
  • Fsync 针对单个⽂件操作,做强制硬盘同步,fsync 将阻塞直到数据写⼊到硬盘。
  • 配置为 always 时,每次写⼊都要同步 AOF ⽂件,性能很差,在⼀般的 SATA 硬盘上,只能⽀持⼤约⼏百 TPS 写⼊。除⾮是⾮常重要的数据,否则不建议配置。
  • 配置为 no 时,由于操作系统同步策略不可控,虽然提⾼了性能,但数据丢失⻛险⼤增,除⾮数据重要程度很低,⼀般不建议配置。
  • 配置为 everysec,是默认配置,也是推荐配置,兼顾了数据安全性和性能。理论上最多丢失 1 秒的数据。

9. AOF 的重写机制

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

重写的 AOF 文件为什么可以变小。有以下几个原因:

  • 进程内超时的数据不再写入文件
  • 旧的 AOF 中的⽆效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版本。
  • 多条写操作合并为⼀条,例如 lpush list a、lpush list b、lpush list 从可以合并为 lpush list a b
    c。

较小的 AOF 文件一方面减少了硬件空间的使用,另一方面提供了启动 Redis 数据恢复的速度

AOF 重写机制可以分为手动触发和自动触发:

  • 手动触发:调用 bgrewriteaof 命令
  • 自动触发:根据 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 参数决定自动触发时机。auto-aof-rewrite-min-size:表⽰触发重写时 AOF 的最⼩⽂件⼤⼩,默认为 64MB。auto-aof-rewrite-percentage:代表当前 AOF 占⽤⼤⼩相⽐较上次重写时增加的⽐例。

下面我们来看一下 AOF 具体的重写流程

1. 执行 AOF 重写请求

如果当前进程正在执行 AOF 重写,请求不执行。如果当前进程正在执行 bgsave 命令,重写命令延迟到 bgsave 结束后再执行

2. 父进程执行fork 创建子进程

3. 重写

  • 主进程 fork 之后,继续响应其他命令。所有修改操作写⼊ AOF 缓冲区(aof_buf)并根据 appendfsync 策
    略同步到硬盘,保证旧 AOF ⽂件机制正确。
  • ⼦进程只有 fork 之前的所有内存信息,⽗进程中需要将 fork 之后这段时间的修改操作写⼊
    AOF 重写缓冲区(aof_rewrite_buf)中。

4. 子进程依据内存快照,将内容合并到新的 AOF 文件中去

5. 子进程完成重写

  • 新⽂件写⼊后,⼦进程发送信号给⽗进程。
  • ⽗进程把 AOF重写缓冲区内(aof_rewrite_buf)临时保存的命令追加到新 AOF ⽂件中。
  • ⽤新 AOF ⽂件替换⽼ AOF ⽂件。
AOF 重写时还有一个很有趣的操作:
前面提到 AOF 文件是按照文本的方式进行写入文件的,后续加载的成本比较高,而 RDB 文件则是采用二进制的方式写入,所以 Redis 就进行了混合,引入了“混合持久化”的方法:还是按照aof的方式,只不过在 AOF 文件重写的时候,将现在的快照内容,以二进制的方式写入 AOF 文件中去,后续再进行的操作则是按照文本的方式写入,然后在下次重写时再次按照二进制的方式将快照内容写入新的 AOF 文件中。
要想实现这种 “混合持久化” 的方法,需要我们手动设置配置文件中的选项并重启 Redis 服务器:

10. 启动时数据恢复

上面就是我们的两种重启机制,下面我们来看一下我们的数据如何在服务重启时完成恢复:

11. 总结

回顾:

  • Redis 提供了两种持久化⽅案:RDB 和 AOF。
  • RDB 视为内存的快照,产⽣的内容更为紧凑,占⽤空间较⼩,恢复时速度更快。但产⽣ RDB 的开销较⼤,不适合进⾏实时持久化,⼀般⽤于冷备和主从复制。
  • AOF 视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF ⽂件。
  • RDB 和 AOF 都使⽤ fork 创建⼦进程,利⽤ Linux ⼦进程拥有⽗进程内存快照的特点进⾏持久化,尽可能不影响主进程继续处理后续命令。

感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值