您的位置:首页 > 数据库 > Redis

redis持久化文件+持久化机制(rdb和aof)+aof重写机制+redis4.0后混合持久化机制

2020-07-12 17:24 295 查看

本文将学习redis持久化文件和持久化机制(RDB、AOF)

一.redis持久化文件

redis持久化文件默认为dump.rdb和appendonly.aof,默认都在./目录下,这两个在redis.conf配置文件中有定义:

# rdb持久化文件名
dbfilename dump.rdb

# 工作目录。持久化文件会生成到这个目录下,可以修改为固定地址
dir ./

#是否开启aof,默认不开启

appendonly no

#aof持久化文件名,默认不开启aof也不会生成aof文件

appendfilename "appendonly.aof"

那么持久化文件有什么作用呢,什么时候生成的呢?这个文件的作用顾名思义就是进行redis数据持久化的,简单来说就是redis将数据从内存保存到磁盘中,下次服务重新启动时会根据持久化文件将上一次服务在线时的数据从这个持久化文件中重新加载恢复。

二.redis持久化机制之RDB

(1)什么是RDB?

redis的rdb持久化机制原理是redis会单独创建(folk)一个和主进程一模一样的子进程来进行持久化操作,这个子进程的所有数据局(变量,环境变量,程序计数器等)都跟原进程一样。当触发rdb操作时,redis会先将要持久化的数据写到一个临时文件中,等持久化结束之后再将这个临时文件替换上一次持久化好的文件,整个过程都由子进程完成,主进程不再进行任何io操作,从而保证了极高的性能。

(2)什么时候folk子进程,持久化时产生临时文件对上一次持久化好的文件进行替换,主进程在持久化时不再参与io操作,怎么验证?

我们知道,redis是一个单线程的高性能缓存key-value数据库。这里说的单线程实际上是指在接收网络请求时是单线程处理的,如下图三个客户端redis-cli同时发送命令过来时redis会将这多个同时过来的命令进行排队,然后按照排队顺序一个个往下执行,而将排队的命令取出来进行处理或持久化的过程中就不一定是单线程完成了,因此单线程的概念是对客户端网络请求处理时而言的,整个redis的工作过程并非完全是单线程完成的,同时也就没有并发问题。

上面简单介绍了RDB机制的原理过程,我们知道当触发rdb操作时,redis会先将要持久化的数据写到一个临时文件中,等持久化结束之后再将这个临时文件替换上一次持久化好的文件,整个过程都由子进程完成,主进程不再进行任何io操作,从而保证了极高的性能。那么我们要怎么验证这几个问题呢?下面通过预先在dump.rdb文件中存放百万条数据重新恢复到redis中,然后进行触发rdb操作通过查看触发前、中、后这几个时间差内产生的文件和现象来验证这个结论。

首先,通过java代码往redis中写入500万条记录:

[code]<!-- 在pom依赖中添加jedis依赖 -->
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
[code]package com.redis.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import java.util.stream.IntStream;
/**
* 新增500万条redis记录
*/
public class RedisTest {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.0.102", 6378);
Pipeline pipeline = jedis.pipelined();
long startTime = System.currentTimeMillis();
IntStream.range(0, 5000000).forEach(it -> pipeline.set("batch" + it, it + ""));
pipeline.syncAndReturnAll();
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
}

然后在redis中就能查询到数据量:

然后进行shutdown操作,就会触发rdb机制,将这500万条记录持久化到rdb文件中:

接下来开启两个命令窗口验证上述三个结论:什么时候folk子进程,持久化时产生临时文件对上一次持久化好的文件进行替换,主进程不再参与io操作。

(a)什么时候folk子进程:当rdb机制触发进行持久化操作时,会folk一个子进程做持久化操作,可以使用bgsave命令手动触发rdb持久化操作,在持久化操作之前,进行中以及结束后通过查看这三个过程的redis进程即可得出结论,在执行bgsave持久化操作时,确实folk了一个子进程进行持久化操作,当持久化操作结束后这个子进程也自动被释放:

(b)持久化时产生临时文件对上一次持久化好的文件进行替换:这个结论的意思是在做持久化操作时,不会将数据直接写到rdb持久化文件中,而是写到一个名为temp-XXX.rdb临时文件中,最后再将这个临时文件替换原来的rdb文件,验证方式和上面类似,都是通过持久化前、中、后三个阶段看redis持久化目录下文件的变化:

(c)主进程在持久化时不再参与io操作:这个直接验证并不好验证,可以操作间接方式进行验证。我们知道redis是单线程,如果说主进程在参与了持久化操作过程,在持久化过程中如果有一个新的客户端请求到达,会怎么样呢?这里可以直接通过save命令进行验证,这个命令就不会folk子进程,而是直接用主进程进行持久化。那么我们可以使用save命令持久化,然后同时再发起一个新的客户端请求,查看这个结果我们可以看到在save使用主进程持久化时,其它的客户端请求都会被阻塞(例如这里新客户端请求set v1 k1就因为使用了主进程进程rdb持久化而阻塞了14.58s),这是非常致命的,也因此redis不会使用主进程进行rdb的持久化,也间接说明了主进程在这个过程中不再参与任何io操作:

(3)什么时候触发RDB机制?

那么有哪些场景会触发rdb呢?在shutdown如果没有开启aof时会触发;配置文件中设置了快照配置时也会触发;执行bgsave或save时也会触发,其中bgsave是redis后台异步进行快照操作,save只进行保存同时会阻塞全部请求。由于rdb触发非常消耗性能,因此一般不会设置太频繁的触发策略。

(4)rdb文件内容格式?

rdb文件内容格式是二进制的存储格式,通过vi dump.rdb查看:

三.redis持久化机制之AOF

(1)什么是aof,为什么会出现aof?

在aof机制中redis操作日志以追加的方式写入文件,其中读操作不做记录。之所以出现aof是因为rdb方式在快照配置中假设默认60s查看触发一次rdb,但是在这60s内假设突然发生了宕机,那么后果就是在这60s内产生的redis数据都没有被持久化下来,从而造成数据的丢失,为了弥补这种意外情况发生导致数据丢失的问题,因此就出现了aof,而aof由于每秒操作因此极端情况下丢失的数据极少。

(2)持久化文件在哪里,怎么配置触发条件,文件数据格式是怎么样的?

aof持久化是将命令字符串(读操作除外)记录到文件中,因此这个aof持久化实际存的就是一个个命令字符串,位置也是在dir配置目录下,文件名默认为appendonly.aof,同时aof也是默认关闭,要想使用aof持久化机制则需要开启。

在redis.conf配置文件中配置触发条件(默认每秒触发):

开启aof机制后,往redis中写入几条记录,通过vi查看aof持久化文件:

接下来让我们解析这个aof持久化文件的存储格式,上面是通过set k1 v1和set k2 v2后得到的aof持久化文件,备注如下#部分。

*2     #表示接下来有几组命令:2组
$6    #接下来命令长度:6个字符
SELECT  #SELECT:刚好6个字符
$1    #加下来命令长度:1个字符
0      #0:刚好1个字符
*3    #接下来有3组命令
$3    #接下来命令长度为3
set   #set
$2    #接下来命令长度为2
k1    #k1
$2    #接下来命令长度为2
v1   #v1
*3   #接下来有3组命令
$3  #接下来命令长度为3
set  #set
$2  #接下来命令长度为2
k2  #k2
$2  #接下来命令长度为2
v2  #v2

因此,经过上面逐行解析,我们很自然可以得到上面这一组aof存储字符所表示的含义就是:select 0;set k1 v1;set k2 v2,其中select 0是选取redis的第一个数据库进行存储,是文件自动添加上去的。

(3)aof重写机制?

aof重写机制的出现目的是给aof持久化文件瘦身,因为随着时间推移aof文件会变得越来越大。但是在aof文件内存储的字符指令实际上是可以进行合并重写的。

触发时机是当aof文件大小增长到一定大小时(默认64mb)redis能够调用bgrewriteaof对日志文件进行重写,当aof文件的增长率大于该配置项时自动开启重写(这里指超过原大小的100%)。

auto-aof-percentage 100   #当aof增长率大于100%时也会自动触发

auto-aof-rewrite-min-size 64mb  #这个大小是第一次文件大小触发,一般生产环境都要改大,如5G

那么配置了上述两个参数,触发重写后下一次触发文件大小就是:64mb * (1+100%) = 128mb,也就是下一次文件大小达到128mb时就再一次触发重写机制,重写也会folk子进程造成较大开销,因此第一次文件触发大小一般都应设置较大。

aof重写机制流程:

在重写发生时,首先主进程会判断是否当前有子进程可以进行重写操作,如果有则直接使用子进程,如果没有则folk一个子进程;主进程和子进程分别依旧进行自己的任务,主进程folk的子进程依旧进行旧aof文件的记录,另一个folk产生的子进程则负责重写任务。在重写过程中,重写子进程会将当前内存中的所有数据进行aof重写并生成到新的aof文件中,如果重写过程中有新的请求发生那么新请求日志会放在aof-rewrite-buf缓冲区中,重写子进程会将aof-rewrite-buf缓冲区中新的请求日志追加到新aof文件中,最后覆盖旧的aof文件。

(4)aof和rdb同时存在时怎么工作?

当设置了aof和rdb机制同时存在时,会以aof机制作为首要考虑,具体过程见下图所示:

当配置了aof时就会以aof持久化文件启动,如果加载aof文件成功则启动成功,否则启动失败;当没有开启aof机制则判断是否存在rdb文件,如果存在rdb文件夹加载rdb文件,如果加载rdb文件成功则启动成功,否则启动失败。

验证:本例中同时存在rdb持久化文件dump.rdb(500万条记录),appendonly.aof(2条记录),那么我们重新启动redis查看记录总数,可以看到只会有2条说明是优先加载aof持久化文件的:

那么有一种场景:假设原本是使用rdb持久化的,但是后面要切换为aof持久化,为了让rdb文件的数据不丢失,应该怎么操作将rdb文件的数据迁移到aof文件中呢?

做法就是先关闭aof机制,启动加载rdb文件先让数据加载到redis内存当中,然后通过命令config set appendonly yes动态开启aof机制,这样在生成的aof文件就会把当前内存的redis数据持久化到aof文件中了。接下来shutdown关闭redis,最后再到redis.conf配置文件中重新开启aof机制并重启redis服务即可。

aof和rdb优缺点比较:

aof:数据丢失少,性能慢,不适合大数据导入;

rdb:数据丢失多,性能快,适合大数据导入。

aof和rdb都可以设置每一秒进行持久化,哪有什么区别呢?

rdb可以设置save参数进行每秒持久化,但是rdb会folk子进程进行持久化导致开销会很大,相当于又创建了一个redis进程;

aof的持久化是不会folk子进程的因此性能开销更小,而aof重写才会folk子进程,aof持久化和aof重写是两个不同操作注意区分开。

四.redis4.0之后混合持久化机制?

在redis4.0之后是混合持久化机制,在4.0默认是关闭的,5.0之后默认是开启的。配置文件中通过aof-use-rdb-preamble参数控制,yes为开启no为关闭。混合持久化是通过bgrewriteaof完成的,不同的是当开启混合持久化时,folk出的子进程先将共享的内存副本全量以rdb方式写入aof文件,然后再将从写缓冲区增量命令以aof的方式写入文件,写入完成后通知主进程更新统计信息,并将新的含有rdb格式和aof格式的aof文件替换旧的aof文件。简单而言,新的aof文件前半段是rdb格式的全量数据,后半段是aof格式的增量数据。

优点:混合持久化结合了rdb和aof的优势,由于绝大多数都是rdb二进制格式,因此加载快,同时结合aof保存增量数据使得数据丢失少;

缺点:兼容性差,一旦开启混合持久化,那么4.0之前的版本都不能识别这个混合持久化文件,同时前半段包含rdb二进制格式会导致阅读性差。

混合持久化机制的过程:当进行aof重写时,对于历史数据则以rdb方式重新存储到aof文件中,重写完成后的数据还是以aof方式存储到aof文件中,因此也可以对aof文件进行瘦身。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: