Redis(六)--Redis持久化方式+原理+区别

Redis(六)–Redis持久化方式+原理+区别

一、持久化:

什么是持久化?

Redis所有数据保存在内存中,对数据的更新将异步地保存到磁盘上,使得数据在Redis重启之后仍然存在。这么做这有什么实际意义呢?将数据存储到硬盘是为了以后可以重用数据,将数据进行备份,可以在系统故障的时候从备份进行恢复。还有一点,存储在Redis里面的数据可能是经过复杂运算而得出的结果,把这些数据进行存储,方便后续的使用,以达到“空间换时间”的效果。

为什么需要持久化?

redis里有10gb数据,突然停电或者意外宕机了,再启动的时候10gb都没了?!所以需要持久化,宕机后再通过持久化文件将数据恢复

持久化的实现方式:

Redis提供了两种不同的持久化方法将数据保存到硬盘里面。

1.快照持久化:将Redis某一时刻存在的所有数据都写入硬盘。

  • MySQL Dump
  • Redis RDB

2.AOF持久化:AOF的全称叫append-only file,中文意思是只追加文件。当使用AOF持久化方式的时候,Redis执行写命令的时候,将被执行的写命令复制到硬盘里面,说的通俗一点就是写日志

二、快照持久化

2.1 什么是快照持久化

Redis通过创建快照来获得存储在内存里面的数据在某个时间节点上的副本

2.2什么是RDB?

Redis(六)--Redis持久化方式+原理+区别_第1张图片
redis主从复制的时候,也会用到RDB

2.3 触发机制-主要三种方式:

  • save(同步)
  • bgsave(异步)
  • 自动

2.4 save(同步):

客户端向Redis发送save命令来创建一个快照文件。

  • 在数据量很大的时候,会存在阻塞因为redis是单线程的

  • 文件策略:如果存在老的RDB文件,新的文件会替换老的文件

  • 复杂度:O(N),因为需要将redis中的所有数据都写在RDB文件中

Redis(六)--Redis持久化方式+原理+区别_第2张图片

缺点:

致命的问题,持久化的时候redis服务阻塞(准确的说会阻塞当前执行save命令的线程,但是redis是单线程的,所以整个服务会阻塞),不能继对外提供请求,GG!数据量小的话肯定影响不大,数据量大呢?每次复制需要1小时,那就相当于停机一小时。

2.5 bgsave(异步):

客户端向Redis发送bgsave命令,Redis调用fork创建一个子进程,然后子进程负责将快照写入硬盘,而父进程则继续处理命令请求

Redis(六)--Redis持久化方式+原理+区别_第3张图片
这个createRDB是由子进程来完成的。

优点:

他可以一边进行持久化,一边对外提供读写服务,互不影响,新写的数据对我持久化不会造成数据影响,你持久化的过程中报错或者耗时太久都对我当前对外提供请求的服务不会产生任何影响。持久化完会将新的rdb文件覆盖之前的。

save命令和bgsave命令对比:

Redis(六)--Redis持久化方式+原理+区别_第4张图片
2.6 自动:

通过配置,满足任何一个条件就会创建快照文件。(在某些条件达到的时候,自动地生成RDB文件 (这个条件可以在配置文件中配置))

Redis(六)--Redis持久化方式+原理+区别_第5张图片
上面表格中满足任意条件就会自动创建RDB,这里面第一行的意思是:每900秒,有一个数据改变,就会生成RDB文件。

快照持久化现存问题

耗时、耗性能:通过bgsave命令进行持久化的的时候,需要fork一个子进程,如果数据量很大的话,需要的内存也会相应的变大,内存的占用会导致Redis性能降低。

不可控、丢失数据:举个例子,上一次创建快照是11:00开始创建并创建成功。如果Redis在12:00开始创建新的快照,如果系统在未完成创建快照之前崩溃,11:00-12:00写入的数据将会丢失;如果系统在快照创建完成之后崩溃,那么12:00之后,创建快照的过程中的数据将会丢失。

疑问?

会同时存在多个子进程吗?

不会主进程每次收到bgsave命令需要fork()子进程之前都会判断是否存在子进程了,若存在也会忽略掉这次bgsave请求。若不存在我会fork()出子进程进行工作

为什么这么设计?

猜测原因如下:

如果支持并行存在多个子进程,那么不仅会拉低服务器性能,还会造成数据问题,比如八点的bgsave在工作,九点又来个bgsave命令。这时候九点的先执行完了,八点的后执行完了,那九点的不白执行了吗?这是我所谓的数据问题。再比如,都没执行完,十点又开一个bgsave,越积越多,服务器性能被拉低。

那为什么不阻塞?判断有子进程在工作,就等待,等他执行完我在上场,那一样,越积越多,文件过大,只会造成堆积

补充:

在 Redis 服务中,子进程只会读取共享内存中的数据,它并不会执行任何写操作,只有主进程会在写入时才会触发这一机制,而对于大多数的 Redis 服务或者数据库,写请求往往都是远小于读请求的,所以使用fork()加上写时拷贝这一机制能够带来非常好的性能,也让BGSAVE这一操作的实现变得很简单。

三、AOF持久化

3.1 RDB现存问题:
Redis(六)--Redis持久化方式+原理+区别_第6张图片
Redis(六)--Redis持久化方式+原理+区别_第7张图片
Redis(六)--Redis持久化方式+原理+区别_第8张图片

3.2 什么是AOF:

它也是Redis持久化的重要手段之一,aof->Append Only File,只追加文件,也就是每次处理完请求命令后都会将此命令追加到aof文件的末尾。而RDB是压缩成二进制等时机开子进程去干这件事

Redis(六)--Redis持久化方式+原理+区别_第9张图片
Redis(六)--Redis持久化方式+原理+区别_第10张图片
主要写入一个数据,就向AOF文件中增加一条数据

3.3 AOF的三种策略:

  • always:每条Redis写命令都同步写入硬盘。
    Redis(六)--Redis持久化方式+原理+区别_第11张图片
  • everysec:每秒执行一次同步,将多个命令写入硬盘。

Redis(六)--Redis持久化方式+原理+区别_第12张图片

  • no:由操作系统决定何时同步。

Redis(六)--Redis持久化方式+原理+区别_第13张图片
三种策略对比:生产环境中需要根据实际的需求进行选择。

在这里插入图片描述

  • always:同步持久化,每次发生数据变更会被立即记录到磁盘(性能较差,数据完整性较好)(效率最慢,但也是安全性最高的

  • everysec:效率挺快的,就算出现故障,数据库也只是丢失一秒钟的命令数据。(默认推荐,,异步操作,每秒记录,若一秒钟内宕机,又数据丢失

  • no:与 everysec效率相当,但是出现故障时,将丢失上次同步AOF文件之后的所有写命令数据

3.4 AOF重写:

随着Redis的运行,被执行的写命令不断同步到AOF文件中,AOF文件的体积越来越大,极端情况将会占满所有的硬盘空间。如果AOF文件体积过大,还原的过程也会相当耗时。为了解决AOF文件不断膨胀的问题,需要移除AOF文件中的冗余命令来重写AOF

Redis(六)--Redis持久化方式+原理+区别_第14张图片

AOF重写的两种实现方式:

  • bgrewriteaof命令
  • AOF重写配置

bgrewriteaof命令:
bgrewriteaof命令和bgsave命令的工作原理相似:

首先从数据库中读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理
Redis(六)--Redis持久化方式+原理+区别_第15张图片
AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点相似。

因为新的aof文件只包含还原当前数据库状态所必须的命令,所以新的AOF文件不会浪费任何的硬盘空间

触发机制:
reids会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件>64M时触发

这个为原理图:

Redis(六)--Redis持久化方式+原理+区别_第16张图片

  • aof_rewrite_buf:rewrite(重写)缓冲区、aof_buf:写命令存放的缓冲区
  • 开始bgrewriteaof的时候,判断当前有没有bgsave/bgrewriteaof在执行,若有,则不执行。
  • 主进程fork()出子进程,在执行fork()这个方法的时候是阻塞的,子进程创建完毕后就不阻塞了
  • 主进程fork完子进程后,主进程能继续接收客户端的请求,所有写命令依然是写入AOF文件缓冲区并根据配置文件的策略同步到磁盘的。
  • 因为fork的子进程仅仅共享主进程fork()时的内存,后期主进程在更改内存数据,子进程是不可见的。因此Redis采取重写缓冲区(aof_rewite_buf)保存fork之后的客户端请求。防止新AOF文件生成期间丢失主进程执行的新命令所生成的数据。所以此时客户端的写请求不仅仅写入原来的aof_buf缓冲区,还写入了重写缓冲区。这就是我为什么用深蓝色的框给他两框到一起的原因。
  • 子进程通过内存快照的形式,开始生成新的aof文件。
  • 新aof文件生成完后,子进程向主进程发信号。
  • 主进程收到信号后,会把重写缓冲区(aof_rewite_buf)中的数据写入到新的AOF文件(主要是避免这部分数据丢失)
  • 使用新的AOF文件覆盖旧的AOF文件,且标记AOF重写完成。

AOF重写配置:

配置参数说明:

在这里插入图片描述
具体配置:

appendonly yes
appendfilename "appendonly-${port}.aof"
appendfsync everysc
dir /bigdiskpath
no-appendfsync-on-rwrite yes
auto-aof-rewrit-percentage 100
auto-aof-rewrite-min-size 64mb

3.5 优缺点:

1、优点

持久化的速度快,因为每次都只是追加,rdb每次都全量持久化
数据相对更可靠,丢失少
,因可以配置每秒持久化、每个命令执行完就持久化

2、缺点

灾难性恢复的时候过慢,因为aof每次都只追加原命令,导致aof文件过大,但是后面会rewrite,但是相对于rdb也是慢的。
会对主进程对外提供请求的效率造成影响,接收请求、处理请求、写aof文件这三步是串行原子执行的。而非异步多线程执行的。Redis单线程!

四、RDB和AOF的抉择:

Redis(六)--Redis持久化方式+原理+区别_第17张图片

选择

在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用快照持久化或AOF持久化的一种,或同时开启快照持久化和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机master和从机slave可以独立的选择持久化方案

(1)如果Redis中的数据完全丢弃也没有关系(如Redis完全用作DB层数据的cache),那么无论是单机,还是主从架构,都可以不进行任何持久化。

(2)在单机环境下(对于个人开发者,这种情况可能比较常见),如果可以接受十几分钟或更多的数据丢失,选择快照持久化对Redis的性能更加有利;如果只能接受秒级别的数据丢失,应该选择AOF。

(3)但在多数情况下,我们都会配置主从环境,slave的存在既可以实现数据的热备,也可以进行读写分离分担Redis读请求,以及在master宕掉后继续提供服务。在这种情况下,一种可行的做法是:master:完全关闭持久化,这样可以让master的性能达到最好 slave:关闭快照持久化,开启AOF(如果对数据安全要求不高,开启快照持久化关闭AOF也可以),并定时对持久化文件进行备份(如备份到其他文件夹,并标记好备份的时间);然后关闭AOF的自动重写,然后添加定时任务,在每天Redis闲时(如凌晨12点)调用bgrewriteaof

五、小总结:

RDB:

  • RDB是一个非常紧凑的文件
  • RDB在保存RDB文件时,主进程唯一要做的是:fork出一个子进程,接下来的工作全部交由子进程来做,父进程不需要在做其他IO操作,所以,RDB持久化方式是可以最大化redis的性能。
  • 与AOF相比,在恢复大数据集的时候,RDB文件会更快一些
  • 数据丢失风险大
  • RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大时,fork的进程是非常耗时的,可能会导致redis在一些毫秒级不能响应客户端的请求

AOF:

  • AOF文件是一个只进行追加的日志文件
  • redis可以在AOF文件体积变得过大时,自动地后台对AOF进行重写
  • AOF文件有序地保存了对数据执行的所有写入操作,这些写入操作以redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析是很轻松的
  • 对于相同的数据集来说,AOF文件的体积通常>RDB文件的体积
  • 根据所使用的fsync策略,AOF的速度可能会慢于RDB

也就是说:

redis> SET msg "hello"
OK

redis> SADD fruits "apple" "banana" "cherry"
(integer)3

redis> RPUSH numbers 128 256 512
(integer)3

RDB持久化保存数据库状态的方法是将msg、fruits、numbers三个键的键值对来保存到RDB文件中,而AOF持久化保存数据库状态的方法是将服务器执行的SET、SADD、RPUSH三个命令保存到AOF文件中。

RDB持久化是通过保存数据库中的键值对来记录数据库状态不同。而AOF持久化是通过保存redis服务器所执行的写命令来记录数据库状态的

感谢并参考:
java知音
https://blog.csdn.net/xiaojie_570/article/details/86368420
https://blog.csdn.net/qfc8930858/article/details/89510632

你可能感兴趣的:(Redis)