Redis的持久化 AOF和RDB

Redis的持久化

前言:此文章是学习Redis 核心技术与实战时做的学习笔记,仅供学习和参考。

Redis如何避免数据丢失?

Redis用作缓存时,数据存储在内存中。一旦服务器宕机,内存中的数据就会全部丢失

一个解决方案是从数据库中恢复数据,但是存在两个问题:1、数据库中的数据是存储在硬盘中的,存取速度相对于内存来说太慢,大大影响了Redis的性能;2、频繁读取数据会给数据库增加压力

因此Redis拥有自己的持久化机制,即 AOF(Append Only File)日志和 RDB 快照。

AOF日志

Redis执行的是写后日志,即先执行命令,把数据写入内存,然后才记录日志。

以 Redis 收到“set testkey testvalue”命令后记录的日志为例,看看 AOF 日志的内容。

3”表示当前命令有三个部分,

每部分都是由“$+数字”开头,后面紧跟着具体的命令、键或值。这里,“数字”表示这部分中的命令、键或值一共有多少字节。例如,“$3 set”表示这部分有 3 个字节,也就是“set”命令。

在这里插入图片描述

为什么采用写后日志?

1、Redis 在向 AOF 里面记录日志的时候,并不会先去对这些命令进行语法检查。所以写后日志可以避免出现记录错误命令的情况,因为能够被Redis执行的命令肯定是正确的命令。

2、它是在命令执行后才记录日志,所以不会阻塞当前的写操作。

AOF 里记录的是 Redis 收到的每一条命令,这些命令是以文本形式保存的。

三种写回策略

  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;

  • Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;

  • No,**操作系统控制的写回:**每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

优缺点

在这里插入图片描述

想要获得高性能,就选择 No 策略;如果想要得到高可靠性保证,就选择 Always 策略;如果允许数据有一点丢失,又希望性能别受太大影响的话,那么就选择 Everysec 策略。

AOF日志文件太大了怎么办?

采用AOF 重写机制,重写就是是根据这个键值对当前的最新状态,为它生成对应的写入命令。比如对一个键进行了多次值更新,原AOF文件中就会记录很多条命令,重写只需要根据最后一次更新的数据,生成相应的写入命令即可,如下图:

在这里插入图片描述

LPUSH u:list “N”, “C”, "D"这一条命令就能实现该数据的恢复,这就**节省了五条命令的空间。**对于被修改过成百上千次的键值对来说,重写能节省更大空间。

AOF 重写会阻塞吗?

AOF 日志主线程写回不同,重写过程是由后台子进程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降

一个拷贝

fork子进程时,子进程是会拷贝父进程的页表,即虚实映射关系,而不会拷贝物理内存。子进程复制了父进程页表,也能共享访问父进程的内存数据了,此时,类似于有了父进程的所有内存数据。

“写实复制”顾名思义,就是在写发生时,才真正拷贝内存真正的数据

两处日志

第一处日志就是指正在使用的 AOF 日志,如果此时有新的写操作,Redis 会把这个操作写到它的缓冲区;

第二处日志,就是指新的 AOF 重写日志。这个操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作
在这里插入图片描述

RDB内存快照 ( Redis DataBase)

因为AOF日志记录的是操作命令,而不是实际的数据,所以,用 AOF 方法进行故障恢复的时候,需要**逐一把操作日志都执行一遍。**如果操作日志非常多,Redis 就会恢复得很缓慢,影响性能。

RDB内存快照。所谓内存快照,就是指内存中的数据在某一个时刻的状态记录,把某一时刻的状态以文件的形式写到磁盘上。

和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。

给哪些内存数据做快照?

Redis使用的是全量快照,即把内存中的所有数据都记录到磁盘中

Redis 提供了两个命令来生成 RDB 文件,分别是 savebgsave

save:在主线程中执行,会导致阻塞

bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。

快照时数据能修改吗?

使用 bgsave 可以避免阻塞,但是避免阻塞和正常处理写操作并不是一回事。此时,主线程的确没有阻塞,可以正常接收请求,但是,为了保证快照完整性,它只能处理读操作,因为不能修改正在执行快照的数据。

Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。

  • 读操作 不影响
  • 写操作 如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,成该数据的副本(键值对 C’)。然后,主线程在这个**数据副本上进行修改。**同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。
  • 既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。

在这里插入图片描述

可以每秒做一次快照吗?

两次快照之间的时间间隔很重要,间隔时间很短,即使某一时刻发生宕机了,因为上一时刻快照刚执行,丢失的数据也不会太多但是如果如果频繁地执行全量快照,也会带来两方面的开销。

一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,容易造成恶性循环

另一方面,**fork 这个创建过程本身会阻塞主线程,**而且主线程的内存越大,阻塞时间越长。如果频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了(所以,在 Redis 中如果有一个 bgsave 在运行,就不会再启动第二个 bgsave 子进程)。

增量快照

增量快照,所谓增量快照,就是指,做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。

增量快照前提是要记住哪些数据被修改了。需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题

为了“记住”修改,引入的额外空间开销比较大。这对于内存资源宝贵的 Redis 来说,有些得不偿失。

在这里插入图片描述

混合使用 AOF 日志和内存快照

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,就不会出现文件过大的情况了,也可以避免重写开销。

在这里插入图片描述

AOF 和 RDB 的选择问题,

  • 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
  • 如果允许分钟级别的数据丢失,可以只使用 RDB;
  • 如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值