Redis(七):持久化:AOF和RDB
迪丽瓦拉
2025-05-31 13:47:28
0

前言

上一篇介绍了 Redis 实现消息队列的三种方式。这节开始介绍 Redis 的持久化问题。

我们都知道 Redis 是基于内存的数据库,而内存又是易失性的,一旦遇到断电或异常重启等问题时,内存中的数据就会丢失。所以 Redis 为了保证数据的可靠性花了不少功夫。Redis 主要是通过 AOF 日志和 RDB 快照来实现持久化的。

Redis 共有三种数据持久化的方式:

  • AOF 日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里;
  • RDB 快照:将某一时刻的内存数据,以二进制的方式写入磁盘;
  • 混合持久化:Redis 4.0 新增的方式,集成了 AOF 和 RBD 的优点;

AOF

Append Only File,Redis 每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里。默认关闭。

AOF 是写后日志,即先执行命令把数据写入内存,再记录日志。(大多数据库采用的是写前日志 WAL(Write Ahead Logging),如 MySQL)

Redis 要求高性能,采用写后日志有两方面好处:

  • 避免额外的检查开销:Redis 在向 AOF 里面记录日志的时候,并不会先去对这些命令进行语法检查,只有能执行成功的命令才会被记录到日志中,否则直接报错。如果先记日志再执行命令的话,日志中就有可能记录了错误的命令,或者需要额外的检查;
  • 不会阻塞当前的写操作;

但是存在两个风险:

  • 执行写操作命令和记录日志是两个过程,如果 Redis 还没来得及将命令写入到硬盘,服务器发生宕机,这个数据就会有丢失的风险
  • 由于写操作命令执行成功后才记录到 AOF 日志,所以不会阻塞当前写操作命令的执行,但是可能会给下一个命令带来阻塞风险

流程

  1. Redis 执行完写操作命令后,会将命令追加到 server.aof_buf 缓冲区(AOF 缓冲区);
  2. 然后通过 write() 系统调用,将 aof_buf 缓冲区的数据写入到 AOF 文件,此时数据并没有写入到硬盘,而是拷贝到了内核缓冲区 page cache,等待内核将数据写入硬盘;
  3. 具体内核缓冲区的数据什么时候写入到硬盘,由内核决定。

写回策略

Redis 提供了 3 种写回硬盘的策略,控制的就是流程的第三步。在 redis.conf 配置文件中的 appendfsync 配置项可以有以下 3 种参数可填:

  • Always:每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘(主进程执行 fsync,阻塞);
  • Everysec:每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘(创建一个异步线程来执行 fsync,每次刷盘前会检查上一秒的刷盘是否完成,如果上一次刷盘未完成,则会阻塞当前刷盘操作);
  • No:不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘(不执行 fsync);

重写机制

AOF 日志是一个文件,随着执行的写操作命令越来越多,文件的大小会越来越大(大部分是无用的历史数据),会带来性能问题。

AOF 是记录每次操作的命令,即使有了重写机制,也会非常大,且在恢复数据时需要一条条重放命令,非常缓慢。

当 AOF 文件的大小超过所设定的阈值后,Redis 就会启用 AOF 重写机制,来压缩 AOF 文件。

AOF 重写机制是在重写时,读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。

重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的,这么做有两个好处:

  • 子进程进行 AOF 重写期间,主进程可以继续处理命令请求,从而避免阻塞主进程;
  • 子进程带有主进程的数据副本,这里使用子进程而不是线程,因为如果是使用线程,多线程之间会共享内存,那么在修改共享内存数据的时候,需要通过加锁来保证数据的安全,而这样就会降低性能。而使用子进程,创建子进程时,父子进程是共享内存数据的,不过这个共享的内存只能以只读的方式,而当父子进程任意一方修改了该共享内存,就会发生「写时复制」,于是父子进程就有了独立的数据副本,就不用加锁来保证数据安全。

在重写 AOF 日志过程中,如果主进程修改了已经存在的数据,就会导致主进程和子进程中的数据不一致。所以 Redis 设置了一个 AOF 重写缓冲区,这个缓冲区在创建 bgrewriteaof 子进程之后开始使用。在重写 AOF 期间,当 Redis 执行完一个写命令之后,它会同时将这个写命令写入到 「AOF 缓冲区」和 「AOF 重写缓冲区」

每条写命令是先写入 AOF 缓冲区,再集中写入到内核缓冲区之后进行刷盘的;而 AOF 重写缓冲区是用于记录在 AOF 重写时新的写命令,之后需要追加到新的 AOF 文件中。所以需要将同一个写命令写入到两个缓冲区中去。

在这里插入图片描述

当子进程完成 AOF 重写工作后,会向主进程发送一条信号,信号是进程间通讯的一种方式,且是异步的。

主进程收到该信号后,会调用一个信号处理函数,该函数主要做以下工作:

  • 将 AOF 重写缓冲区中的所有内容追加到新的 AOF 的文件中,使得新旧两个 AOF 文件所保存的数据库状态一致;
  • 新的 AOF 的文件进行改名,覆盖现有的 AOF 文件。

在 AOF 重写时,Redis 实例仍然会调用后台线程进行 fsync 操作(即使写回策略为 no),将新的 AOF 文件写入磁盘。

为什么重写 AOF 的时候,不直接复用现有的 AOF 文件,而是先写到新的 AOF 文件再覆盖过去?

  1. 父子进程写同一个文件会产生竞争问题,影响父进程的性能。

  2. 因为如果 AOF 重写过程中失败了,现有的 AOF 文件就会造成污染,可能无法用于恢复使用。

在重写日志的整个过程中,主线程会被阻塞的时候有:

  • fork 子进程时,需要拷贝虚拟页表;
  • 发生写时复制时,操作系统会创建页面的副本,并拷贝原有的数据;
  • 主进程追加 AOF 重写缓冲区到新的 AOF 文件中时;

RDB

Redis Database,即快照/内存快照,RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据(二进制数据,使用 LZF 算法进行压缩),因此在 Redis 恢复数据时, RDB 恢复数据的效率会比 AOF 高些,因为直接将 RDB 文件读入内存就可以,不需要像 AOF 那样还需要额外执行操作命令的步骤才能恢复数据。

Redis 提供了两个命令来生成 RDB 文件,分别是 savebgsave,他们的区别就在于是否在「主线程」里执行:

  • 执行了 save 命令,就会在主线程生成 RDB 文件,由于和执行操作命令在同一个线程,会阻塞主线程
  • 执行了 bgsave 命令,会创建一个子进程来生成 RDB 文件,可以避免主线程的阻塞,是 Redis 的默认配置;

Redis 还可以通过配置文件的选项来实现每隔一段时间自动执行一次 bgsave 命令。

# 在配置文件中使用如”save m n”,表示m秒内数据修改n次,自动触发bgsave。
save 900 1
save 300 10
save 60 10000

在执行 debug reload 命令重新加载 Redis,会自动触发 save 操作。在执行 shutdown 命令时,没有开启 AOF 持久化会自动执行 bgsave。

在子进程生成 RBD 文件时,使用了写时复制技术,主线程还是可以工作的。

  • 当主线程对这些共享的内存数据都是只读操作,那么主线程和 bgsave 子进程相互不影响;
  • 如果主线程要修改共享数据里的某一块数据时,就会发生写时复制,于是这块数据的物理内存就会被复制一份,然后主线程在这个数据副本进行修改操作。bgsave 子进程可以继续把原来的数据写入到 RDB 文件,而新写入的数据需要等到下一次写入;

在整个过程中,只有在 fork 子进程时,需要拷贝虚拟页表,主线程会被阻塞。

Redis 的快照是全量快照,也就是说每次执行快照,都是把内存中的「所有数据」都记录到磁盘中。所以频繁执行快照会对性能造成影响,而设置的时间过长又会导致部分数据丢失。

RDB 的优点是恢复速度远快于 AOF、占内存空间小;缺点是要用很大的性能才能换取较好的实时性;

RDB 存在两个风险:

  • 如果系统恰好在 RDB 快照文件创建完毕后崩溃了,那么 Redis 将会丢失主线程在快照期间修改的数据。
  • 主线程修改数据需要复制物理内存,如果所有的共享内存都被修改,则此时的内存占用是原先的两倍。

混合持久化

Redis 4.0 开始支持混合使用 AOF 日志和内存快照,也叫混合持久化。简单来说就是,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

当开启了混合持久化时,在 AOF 重写日志时,重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据

这样的好处在于,重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快

数据恢复

Redis 启动时,会从 AOF 和 RBD 文件中恢复数据,所以如果想要恢复数据,只需重启 Redis 即可。

在这里插入图片描述

最后

本文介绍了 Redis 中的实现数据持久化的方案,主要是 AOF 日志和 RDB 快照。下一节将介绍 Redis 的内存管理。

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...