Redis学习:
https://blog.csdn.net/2301_80220607/category_13051025.html?spm=1001.2014.3001.5482
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命令的流程说明

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