刷新你对Redis持久化的认知

认识持久化

redis是一个内存数据库,数据存储到内存中。而内存的数据是不持久的,要想做到持久化,就需要让redis把数据存储到硬盘上。
因此redis既要在内存上存储一份数据,还要在硬盘上存储一份数据。这样这两份数据在理论上是完全相同的(实际上可能存在一点差异,这取决于咱们怎么进行持久化)。当要插入一个数据的时候,需要同时写入内存和硬盘(实际上怎么写入硬盘有不同的策略);当查询某个数据的时候,直接从内存读取;硬盘的数据只是在redis重启的时候,用来恢复内存中的数据。

redis实现持久化的两种方式

  1. RDB:定期备份
  2. AOF:实时备份

RDB

RDB定期的把redis内存中所有数据,给拍个”照片“,生成快照文件写入硬盘中。一旦redis重启,就可以根据刚才的”快照“把内存的数据给恢复回来。

定期的两种方式

手动触发

程序员通过redis客服端,执行特定命令,触发快照的生成

  1. save命令,执行save时,redis会全力投入到生成“快照”中,阻塞redis其他客服端的命令。因此一般不建议使用save命令
  2. bgsave命令,并不会影响redis服务器处理其他客服端的请求和命令,通过多进程实现,如下图所示:

刷新你对Redis持久化的认知_第1张图片

  1. 执行bgsave命令,父进程会判断是否存在其他正在执行的子进程,例如RDB/AOF子进程,如果存在,bgsave命令会直接返回
  2. 父进程执行fork创建子进程,fork过程中父进程会阻塞,可以通过info status命令查看 latest_fork_usec选项,获取最近一次fork操作耗时,单位ms.

fork是linux提供创建子进程的api,直接把父进程复制一份(pcb,文件描述符表,虚拟地址空间(内存中的数据)),作为子进程。在redis服务器中有若干变量,保存了一些键值对数据,随着fork的进行,子进程内存中也会存在和刚才父进程一样的变量。因此子进程进行“持久化”操作,相当于把父进程的内存数据给持久化了。(父进程打开一个文件,fork之后,子进程也同样使用这个文件;这就导致子进程进行持久化写入的那个文件和父进程本来要写的文件是同一个)
:::tips
fork的“写时拷贝”机制
:::
刷新你对Redis持久化的认知_第2张图片
父进程进行一些修改
刷新你对Redis持久化的认知_第3张图片
bgsave这个场景中,绝大部分内存数据是不需要改变的,因此子进程的“写时拷贝”并不会触发很多次,也就保证了整体的“拷贝时间”是可控的

  1. 父进程fork完成后,bgsave命令返回"Background saving started"信息,不再阻塞父进程,可以继续响应其他命令
  2. 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
  3. 进程发送信号给父进程表示完成,父进程更新统计信息

自动触发

在redis的配置文件redis.conf进行设置,让redis每隔多长时间,每生产多少次修改就触发.

查看redis.conf文件

刷新你对Redis持久化的认知_第4张图片
上述数值可以修改配置,但是不能让rdb操作过于频繁,因为生成一次rdb快照是一个成本比较高的成本。

RDB生成的文件

redis生成的rdb文件,存放在redis的工作目录中,可以在redis.conf中查看该工作目录。
:::tips
cd /etc/
vim redis.conf
:::
刷新你对Redis持久化的认知_第5张图片
切换到该工作目录
:::tips
cd /var/lib/redis/
ll
:::
刷新你对Redis持久化的认知_第6张图片
其中dump.rdb即rdb机制生成的镜像文件,redis服务器默认是开启rdb的。dump.rdb是一个二进制文件,redis将内存中的数据,以压缩的形式,保存到这个二进制文件中。

redis默认采用LZF算法对生成的RDB文件做压缩处理,默认开启,可以在redis.conf文件中修改配置image.png

后续redis服务器重新启动,就会加载dump.rdb文件,在加载时会进行校验,redis提供了rdb文件的检查工具redis-check-rdb
刷新你对Redis持久化的认知_第7张图片
由上图我们发现检查工具和redis服务器在5.0版本是同一个可执行程序,可以在运行的时候加入不同的选项,从而实现不同的功能。例如,运行的时候,加入rdb文件作为命令行参数,此时就是以检查工具的方式运行,不会真的启动redis服务器。
说明dump.rdb文件没有问题,解析正确

生成RDB文件的方式

  1. 手动执行bgsave触发一次生成快照

刷新你对Redis持久化的认知_第8张图片
redis服务器重新启动之后,会加载rdb文件的内容,恢复内存中的数据。
dump.rdb文件如下,虽然我们看不懂二进制文件,但是能看到key1,key2,key3。
image.png

  1. 插入新的key,不手动执行bgsave

刷新你对Redis持久化的认知_第9张图片
由上图可知,如果是通过正常流程重启redis服务器,此时redis服务器在退出的时候,会自动触发rdb操作;如果是异常重启(kill -9/服务器掉电)此时redis服务器来不及生成rdb,内存中尚未保存到快照中的数据,就会随着重启而丢失。
:::info
redis生成快照,不通过手动执行命令,而是自动触发有如下情况

  1. 满足配置文件中超过M秒,修改了N次,触发save操作

刷新你对Redis持久化的认知_第10张图片

  1. 通过shutdown命令(redis正确关闭服务器的命令)也会触发
  2. redis进行主从复制的时候,主节点会自动生成rdb快照,然后把rdb快照文件内容传输给从节点
    :::

观察生成rdb的过程

bgsave通过创建子进程,让子进程完成持久化操作。持久化会把数据写入新的文件中,然后使用新的文件替换旧的文件。由于持久化速度太快(数据量小),难以观察;而新文件替换旧文件是容易观察的。
刷新你对Redis持久化的认知_第11张图片
inode编号是文件的身份标识,两次inode编号不同,说明文件并不是同一个文件,只是内容相同。

linux文件系统的组织方式是ext4,主要将整个文件系统分成3个部分

  1. 超级块,存放一些管理信息
  2. inode区,存放inode节点,每个文件都会分配一个inode数据结构,包含了文件的各种元数据
  3. block区,存放文件的数据内容

RDB的优缺点

  • RDB是一个压缩的二进制文件,代表redis在某个时间点上的数据快照。非常适合用来备份,全量复制等场景。比如每6个小时执行bgsave备份,并把rdb文件复制到远程机器或者文件系统中用于备灾
  • redis加载rdb恢复数据远快于aof方式。因为rdb使用二进制的方式组织数据,直接把数据读到内存中,按照字节的格式取,放到结构体/对象中即可。而aof是使用文本的方式组织数据,则需要进行一系列的字符串切分操作
  • rdb文件使用特定二进制格式保存,当redis版本升级以后,兼容性可能存在风险。

可以遍历旧版本的redis中所有的key,把数据取出来,插入到新的redis服务器中

  • rdb最大的问题就是不能实时持久化保存数据,在两次快照之间,实时的数据可能随着重启而丢失

AOF

aof以独立日志的方式记录每次写的命令,重启时在重新执行aof文件中的命令达到恢复数据的目的。aof主要作用是解决数据持久化的实时性问题,是目前redis持久化的主流方式。

使用AOF

开启aof功能需要在配置文件中设置:appendonly yes默认不开启。当开启aof后,rdb就不生效;启动以后不再读取rdb内容。aof文件名通过appendfilename配置文件中设置。aof文件所在位置和rdb文件所在的目录一样,默认/var/lib/redis(可配置)
刷新你对Redis持久化的认知_第12张图片

向redis中添加key1,key2,key3

刷新你对Redis持久化的认知_第13张图片
刷新你对Redis持久化的认知_第14张图片
查看appendonly.aof文件
刷新你对Redis持久化的认知_第15张图片

appendonly.aof文件记录了你的每一个操作命令,通过一些特殊符号作为分割符,来对命令的细节做出区分。aof文件的格式是文本格式,因为文本协议具备更好的兼容性,事先简单,具备可读性。

AOF的工作流程

刷新你对Redis持久化的认知_第16张图片

aof-buf缓冲区

引入aof机制,既写内存,有写硬盘,速度还会很快吗?

  1. aof机制并不是直接让工作线程把数据写入硬盘,而是先写入内存的缓冲区aof_buf,积累一波后,再统一写入硬盘,降低了写硬盘的次数。写硬盘的时候,一次写入硬盘数据的多少,对于性能影响不是很大,但是写入硬盘的次数影响很大。
  2. 硬盘上读写数据,顺序读写的速度比较快,随机访问的速度比较慢。而aof每次把新的操作写入到原有文件的末尾,属于顺序写入。

把数据写入缓冲区,本质还是在内存中,当进程挂了或者主机掉电,缓冲区的数据会不会丢失?

会,缓冲区中没来得及写入硬盘的数据会丢。
缓冲区的刷新策略
刷新你对Redis持久化的认知_第17张图片

  • always:每一步操作立刻同步到aof文件中,频率最高,数据可靠性最高,性能最低
  • everysec:每秒将缓冲区的数据写入aof文件,频率低一些,数据可靠性降低一些,性能提高一些,默认采用everysec策略image.png
  • no:由操作系统来控制什么时候写入aof文件,频率最低,数据可靠性最低,性能最高

重写机制(rewrite)

随着操作的增多,aof文件体积越来越大。redis启动的时候需要读取aof文件内容,这就会影响到redis启动时间。实际上redis启动的时候,只关注最终结果,并不关心aof文件中记录的中间过程,所以aof文件中有一些内容存在冗余。如下所示:
刷新你对Redis持久化的认知_第18张图片
因此redis就引入了“重写机制”,对aof文件进行整理操作,剔除其中的冗余操作,并且合并一些操作,达到给aof文件瘦身的效果。

触发重写机制
  1. 手动触发:执行bgrewriteaof命令
  2. 自动触发:根据auto-aof-rewrite-min-sizeauto-aof-rewirte-percentage参数确定自动触发时机
    1. auto-aof-rewrite-min-size:表示触发重写时aof的最小文件大小,默认是64Mb
    2. auto-aof-rewrite-percentage:表示当前aof占用大小相比上次重写时增加的比例

image.png

AOF重写流程

刷新你对Redis持久化的认知_第19张图片

序号2和4的过程

aof重写和rdb生成快照文件一样,都是通过多进程的方式。通过fork创建子进程,父进程负责接收请求,子进程负责针对aof文件进行重写。子进程只需要把当前内存中的数据,获取出来,以aof的格式写入到一个新的aof文件中。因为内存中的数据状态,就相当于把aof文件整理后的结果。此处子进程写数据的过程,类似于rdb生成一个镜像快照。只不过rdb是按照二进制的方式生成的,aof重写则是按照aof要求的文本格式生成的,都是把当前内存的所有数据状态给记录到文件中。

序号3.1的过程

子进程写新aof文件的同时,父进程仍然在不停的接收客服端新的请求,父进程会把这些请求先写入aof_buf缓冲区中,再刷新到原有的aof文件中。

序号3.2,5.1, 5.2, 5.3过程

在创建子进程的一瞬间,子进程继承了当前父进程的内存状态。因此子进程中的内存数据是父进程fork之前的状态,fork之后,新的请求,对内存造成的修改,是子进程不知道的。此时,父进程准备了一个aof_rewrite_buf缓冲区,专门放fork之后的数据。子进程把aof数据写完以后,会通过信号通知一下父进程,父进程再把aof_rewrite_buf缓冲区的内容也写到新的aof文件中,到这就可以用新的aof文件替换旧的aof文件。
什么是信号?
信号是linux的神经系统,是进程间通信的一种手段。信号能表达的信息有限,并不像socket可以传输任意数据,图中子进程向父进程发送一个信号,表示“我已经干完了”。
信号包含3部分

  • 信号源:哪个进程发送的
  • 信号类型:例如kill -9 表示给指定进程发送9号信号
  • 信号的处理函数:接收方接到这个信号触发的行为

如果在执行bgrewriteaof时,当前redis已经正在进行aof重写,会咋样?

此时,不会再次执行aof重写,直接返回。

如果在执行bgrewriteaof时,当前redis在生成rdb文件快照,会咋样?

此时aof重写操作会等待,等待rdb快照生成完毕之后,再执行aof重写

父进程fork完成后,子进程开始写入新的aof文件,随着时间推移,子进程写完新的文件后,让新的aof文件替换旧的aof文件。此时父进程仍然继续写入旧的aof文件是否有意义?

预防极端情况,例如服务器挂了,子进程的内存数据都会丢失,新的aof文件内容不完整,所以如果父进程不坚持写入旧的aof文件,重启旧无法保证数据的完整性。

启动时恢复数据

当redis启动时,会根据rdb和aof文件的内容,进行数据恢复,如下图所示:
刷新你对Redis持久化的认知_第20张图片
如果开启aof,以aof为主,忽略rdb文件。因为aof中包含的数据比rdb更全。

混合持久化

aof是按照文本的方式写入文件的,导致后续加载的成本较高。因此redis引入“混合持久化”结合了rdb和aof特点,按照aof的方式,把每个请求/操作都记录到文件中,在触发aof重写之后,就会把当前内存的状态按照rdb的二进制格式写入到新的aof文件中,后续再进行的操作,仍然按照aof文本的方式追加到文件后头。
在redis.conf配置文件中开启混合持久化
image.png
示例:
刷新你对Redis持久化的认知_第21张图片
打开appendonly.aof文件
刷新你对Redis持久化的认知_第22张图片

你可能感兴趣的:(redis,redis,缓存)