Redis学习[3] ——持久化

news/2024/9/25 19:18:19/

四. Redis 持久化

4.1 Redis 如何保证数据不丢失?

由于Redis的数据是保存在内存中,而内存中的数据会在Redis重启后丢失。因此,为了保证数据不丢失,Redis实现了数据持久化的机制。这个机制会将内存中的数据存储到磁盘,重启后可以从磁盘中恢复。

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

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

4.2 AOF 日志是如何实现的?

4.2.1 AOF 日志写入

Redis在执行完一条写操作命令后,就会把该命令以追加写的方式写到一个文件中。当Redis重启后,会读取该文件记录的命令,逐个执行来恢复数据。

请添加图片描述

为什么是先执行命令,然后再把命令写入日志?

Reids 是先执行写操作命令后,才将该命令记录到 AOF 日志里的,这么做其实有两个好处:

  • 避免额外的检查开销:如果先写入再执行,那在写入的时候还无法确定是否能够执行。需要增加一步检查命令。
  • 不会阻塞当前写操作命令的执行:因为是完成写操作再去写入之日。

也会存在风险:

  • 数据可能会丢失:如果完成了写操作但还没来得及写入日志,服务器宕机了,会丢失这个数据;
  • 可能阻塞其他操作:AOF日志也是在主线程中执行的,会阻塞后续的操作等待写入完成;
4.2.2 AOF 日志写回策略

Redis写入AOF日志的过程可以由下图所示:

  1. Redis执行完写操作命令后,会将命令追加到一个缓冲区;
  2. 然后通过write()系统调用,将该缓冲区的命令写入到磁盘中的AOF文件中。实际上这一步只会让命令拷贝到了AOF文件的内核缓冲区,什么时候写入到硬盘由内核决定

Redis提供了3种写回硬盘的策略,控制什么时候将数据写入硬盘

  • Always:每次写操作执行完成后,直接将AOF日志数据写回硬盘;
  • Everysec:写操作执行完成后,数据会先存放在AOF文件的内核缓冲区,每隔一秒将缓冲区的内容写回到磁盘。
  • No:Redis不控制写回的执行,完全交给操作系统来控制

在这里插入图片描述

4.2.3 AOF 重写机制

随着执行的写操作越来越多,AOF日志文件会越来越大,在数据恢复时会越慢,影响性能。因此,Redis提供了重写机制,来避免AOF日志文件越写越大

AOF重写机制是根据K-V数据中的键值对,将每个键值对形成一个命令,记录到「新的 AOF 文件」中,完成后用这个「新的 AOF 文件」替换掉原有的AOF文件。

在这里插入图片描述

AOF重写机制的本质就是**只保留最新的在使用重写机制后,就会读取 name 最新的 value(键值对) ,然后用一条 「set name xiaolincoding」命令记录到新的 AOF 文件,之前的第一个命令就没有必要记录了,因为它属于「历史」命令,没有作用了。这样一来,一个键值对在重写日志中只用一条命令就行了**。

AOF重写是怎么完成的?

Redis是在每次需要AOF重写时,通过**新开辟一个子进程bgrewriteaof来完成AOF重写 **。这是由于:

  • 不会阻塞主进程,主进程可以继续处理命令请求;
  • 如果是多线程,由于共享数据,需要通过锁机制来保证数据安全,会影响性能。而子进程是拷贝数据的副本,创建子进程时,父子进程是共享内存数据的,不过这个共享的内存只能以只读的方式,而当父子进程任意一方修改了该共享内存,就会发生**「写时复制」,于是父子进程就有了独立的数据副本**,就不用加锁来保证数据安全

数据不一致问题?

因为在重写过程中,主进程仍然可以正常处理命令。如果发生了对已有key-value的修改,由于**「写时复制」子进程中关于这个key-value和主进程中的数据出现了不一致。为了解决这个问题,Redis设置了一个AOF重写缓冲区**。

在重写AOF期间,主进程对于所有的写操作命令除了将其加入到**「AOF 缓冲区」,还会加入到「AOF重写缓冲区」。当子进程完成重写时,会向主进程发送一个信号**(进程间的通信方式),主进程收到信号时会执行:

  • 将**「AOF重写缓冲区」中的所有内容追加到「新的 AOF 文件」**中;
  • 用**「新的 AOF 文件」**覆盖掉「旧的 AOF 文件」

截止到此,就完成了整个AOF重写的工作。

4.3 RDB 快照是如何实现的?

Redis使用AOF进行恢复时,如果AOF日志较多,需要逐个执行,势必会使Redis的恢复缓慢。为了解决这个问题,Redis增加了RDB快照。

RDB快照就是记录某一个瞬间的内存数据(是数据而不是命令),由于是直接记录的数据,因此在恢复时不需要执行操作命令,只需要将RDB文件读入内存即可,效率很高

4.3.1 RDB快照生成方法

Redis提供了两个命令来生成RDB快照:savebgsave,它们的区别在于生成快照是否在「主进程」里执行

  • save命令:在主进程中生成RDB快照,如果写入时间太长,会导致主线程阻塞,影响性能;
  • bgsave命令:会创建一个**子进程来生成RDB快照**,避免主线程的阻塞。

Redis 的快照是全量快照,也就是说每次执行快照,都是把内存中的**「所有数据」都记录到磁盘中。所以执行快照是一个比较重的操作,如果频率太频繁,可能会对 Redis 性能产生影响。如果频率太低,服务器故障时,丢失的数据会更多。**

4.3.2 RDB快照如何保证数据一致性?

如果是使用bgsave命令来执行生成快照,此时主进程仍然可以继续处理操作,但是由于快照是在一瞬间的数据,所以不需要去关注是否数据发生了变化。因此,RDB快照不存在数据一致性问题

如果主线程执行写操作,则被修改的数据会复制一份副本,然后 bgsave 子进程会**把原来副本数据写入 RDB 文件(不去管新的),在这个过程中,主线程仍然可以直接修改原来的数据。因此,借助写时复制技术(Copy-On-Write, COW)**,RDB不用关注数据一致性问题。

4.3 为什么会有混合持久化?

😊 RDB 优点是数据恢复速度快,但是快照的频率不好把握。频率太低,丢失的数据就会比较多,频率太高,就会影响性能。

😊 AOF 优点是丢失数据少,但是数据恢复不快。

为了集成了两者的优点, Redis 4.0 提出了混合使用 AOF 日志和RDB快照,也叫混合持久化,既保证了 Redis 重启速度,又降低数据丢失风险。

混合持久化是如何实现的?

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

    当开启了混合持久化,在AOF重写日志时,重写子进程就不是把数据转换成命令写入了,而是**直接生成当时数据库的RDB快照并写入到AOF文件中。然后,主进程中记录在AOF重写缓冲区的命令继续以AOF日志的格式写入到AOF日志文件中**,替换旧的的 AOF 文件。

在这里插入图片描述

混合持久化优点:

  • 混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险

混合持久化缺点:

  • AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差
  • 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了

资料参考

内容大多参考自:图解Redis介绍 | 小林coding (xiaolincoding.com)


http://www.ppmy.cn/news/1502131.html

相关文章

java8函数式接口,以及stream流中map、peek、foreach区别

java8常用函数式接口 import java.util.function.Supplier; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.BiConsumer; import java.util.function.BiFunction;Supplier FunctionalInterface public interface Suppl…

RK3588+MIPI+GMSL+AI摄像机:自动车载4/8通道GMSL采集/边缘计算盒解决方案

RK3588作为目前市面能买到的最强国产SOC,有强大的硬件配置。在智能汽车飞速发展,对图像数据矿场要求越来越多的环境下,如何高效采集数据,或者运行AI应用,成为刚需。 推出的4/8通道GMSL采集/边缘计算盒产品满足这些需求…

docker compose 安装 kafka

一 前置准备 创建 /data/kafkadata /data/zookeeper-1用于保存kafka和zookeeper的配置文件 kafkadata中创建三个文件夹 /kafka1 /kafka2 /kafka3,用于存放三个kafka节点的配置文件 zookeeper-1文件夹中创建 /conf /data /logs /datalog四个文件夹,用于…

【Linux从青铜到王者】tcp协议2

滑动窗口 滑动窗口是什么 上篇提到如果两端发送数据如果是一发一收那就是串行,效率很低,所以可以一次发送多个报文,一次也可以接受多个报文,可以大大的提高性能(其实是将多个段的等待时间重叠在一起了) 那么是怎么发…

打造一篇完美的【数学建模竞赛论文】:从准备到撰写的全面指南

目录 一、赛前准备 1.1 报名与纪律要求 1.2 MD5码上传 1.3 竞赛准备 1.4 时间分配 二、论文格式规范 2.1 摘要 2.2 参考文献 2.3 排版要求 三、建模过程与方法 3.1 问题分析与模型假设 3.2 模型构建与求解 3.3 结果分析与检验 四、论文撰写技巧 4.1 论文结构 4…

opencascade AIS_InteractiveObject源码学习【重中之重】

AIS_InteractiveObject 前言 //! 定义一个具有显示和选择服务的对象类。 //! 被可视化和选择的实体是交互式对象。 //! 实体的特定属性,如尺寸中箭头的外观,必须在 Prs3d_Drawer 中加载。 //! //! 您可以利用已经编写好所有必要方法的标准交互式对象类&…

项目实战_表白墙(简易版)

你能学到什么 一个比较简单的项目:表白墙(简易版),浏览器:谷歌升级版将在下个博客发布 效果如下 正文 说明 我们是从0开始一步一步做这个项目的,里面的各种问题,我也会以第一人称视角来解…

【JAVA】记录一次前端无能造成的 线上bug

有一个需求是 当方式切换 垫资时 清空 当前所选细单商品 但是前端的奇葩 操作是,只是在页面上清空 细单。 不请求 后台删除 细单 让前端 必须 清空同时 请求后台 删除细单 但是 该前端 技术不行, 嫌麻烦 不做 只好 后台 判断该类型时 进行删除操作…