当前位置: 首页 > news >正文

刷新你对Redis持久化的认知

认识持久化

redis是一个内存数据库,数据存储到内存中。而内存的数据是不持久的,要想做到持久化,就需要让redis把数据存储到硬盘上。
因此redis既要在内存上存储一份数据,还要在硬盘上存储一份数据。这样这两份数据在理论上是完全相同的(实际上可能存在一点差异,这取决于咱们怎么进行持久化)。当要插入一个数据的时候,需要同时写入内存和硬盘(实际上怎么写入硬盘有不同的策略);当查询某个数据的时候,直接从内存读取;硬盘的数据只是在redis重启的时候,用来恢复内存中的数据。

redis实现持久化的两种方式

  1. RDB:定期备份
  2. AOF:实时备份

RDB

RDB定期的把redis内存中所有数据,给拍个”照片“,生成快照文件写入硬盘中。一旦redis重启,就可以根据刚才的”快照“把内存的数据给恢复回来。

定期的两种方式

手动触发

程序员通过redis客服端,执行特定命令,触发快照的生成

  1. save命令,执行save时,redis会全力投入到生成“快照”中,阻塞redis其他客服端的命令。因此一般不建议使用save命令
  2. bgsave命令,并不会影响redis服务器处理其他客服端的请求和命令,通过多进程实现,如下图所示:

image.png

  1. 执行bgsave命令,父进程会判断是否存在其他正在执行的子进程,例如RDB/AOF子进程,如果存在,bgsave命令会直接返回
  2. 父进程执行fork创建子进程,fork过程中父进程会阻塞,可以通过info status命令查看 latest_fork_usec选项,获取最近一次fork操作耗时,单位ms.

fork是linux提供创建子进程的api,直接把父进程复制一份(pcb,文件描述符表,虚拟地址空间(内存中的数据)),作为子进程。在redis服务器中有若干变量,保存了一些键值对数据,随着fork的进行,子进程内存中也会存在和刚才父进程一样的变量。因此子进程进行“持久化”操作,相当于把父进程的内存数据给持久化了。(父进程打开一个文件,fork之后,子进程也同样使用这个文件;这就导致子进程进行持久化写入的那个文件和父进程本来要写的文件是同一个)
:::tips
fork的“写时拷贝”机制
:::
image.png
父进程进行一些修改
image.png
bgsave这个场景中,绝大部分内存数据是不需要改变的,因此子进程的“写时拷贝”并不会触发很多次,也就保证了整体的“拷贝时间”是可控的

  1. 父进程fork完成后,bgsave命令返回"Background saving started"信息,不再阻塞父进程,可以继续响应其他命令
  2. 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
  3. 进程发送信号给父进程表示完成,父进程更新统计信息

自动触发

在redis的配置文件redis.conf进行设置,让redis每隔多长时间,每生产多少次修改就触发.

查看redis.conf文件

image.png
上述数值可以修改配置,但是不能让rdb操作过于频繁,因为生成一次rdb快照是一个成本比较高的成本。

RDB生成的文件

redis生成的rdb文件,存放在redis的工作目录中,可以在redis.conf中查看该工作目录。
:::tips
cd /etc/
vim redis.conf
:::
image.png
切换到该工作目录
:::tips
cd /var/lib/redis/
ll
:::
image.png
其中dump.rdb即rdb机制生成的镜像文件,redis服务器默认是开启rdb的。dump.rdb是一个二进制文件,redis将内存中的数据,以压缩的形式,保存到这个二进制文件中。

redis默认采用LZF算法对生成的RDB文件做压缩处理,默认开启,可以在redis.conf文件中修改配置image.png

后续redis服务器重新启动,就会加载dump.rdb文件,在加载时会进行校验,redis提供了rdb文件的检查工具redis-check-rdb
image.png
由上图我们发现检查工具和redis服务器在5.0版本是同一个可执行程序,可以在运行的时候加入不同的选项,从而实现不同的功能。例如,运行的时候,加入rdb文件作为命令行参数,此时就是以检查工具的方式运行,不会真的启动redis服务器。
说明dump.rdb文件没有问题,解析正确

生成RDB文件的方式

  1. 手动执行bgsave触发一次生成快照

image.png
redis服务器重新启动之后,会加载rdb文件的内容,恢复内存中的数据。
dump.rdb文件如下,虽然我们看不懂二进制文件,但是能看到key1,key2,key3。
image.png

  1. 插入新的key,不手动执行bgsave

image.png
由上图可知,如果是通过正常流程重启redis服务器,此时redis服务器在退出的时候,会自动触发rdb操作;如果是异常重启(kill -9/服务器掉电)此时redis服务器来不及生成rdb,内存中尚未保存到快照中的数据,就会随着重启而丢失。
:::info
redis生成快照,不通过手动执行命令,而是自动触发有如下情况

  1. 满足配置文件中超过M秒,修改了N次,触发save操作

image.png

  1. 通过shutdown命令(redis正确关闭服务器的命令)也会触发
  2. redis进行主从复制的时候,主节点会自动生成rdb快照,然后把rdb快照文件内容传输给从节点
    :::

观察生成rdb的过程

bgsave通过创建子进程,让子进程完成持久化操作。持久化会把数据写入新的文件中,然后使用新的文件替换旧的文件。由于持久化速度太快(数据量小),难以观察;而新文件替换旧文件是容易观察的。
image.png
inode编号是文件的身份标识,两次inode编号不同,说明文件并不是同一个文件,只是内容相同。

linux文件系统的组织方式是ext4,主要将整个文件系统分成3个部分

  1. 超级块,存放一些管理信息
  2. inode区,存放inode节点,每个文件都会分配一个inode数据结构,包含了文件的各种元数据
  3. block区,存放文件的数据内容

RDB的优缺点

  • RDB是一个压缩的二进制文件,代表redis在某个时间点上的数据快照。非常适合用来备份,全量复制等场景。比如每6个小时执行bgsave备份,并把rdb文件复制到远程机器或者文件系统中用于备灾
  • redis加载rdb恢复数据远快于aof方式。因为rdb使用二进制的方式组织数据,直接把数据读到内存中,按照字节的格式取,放到结构体/对象中即可。而aof是使用文本的方式组织数据,则需要进行一系列的字符串切分操作
  • rdb文件使用特定二进制格式保存,当redis版本升级以后,兼容性可能存在风险。

可以遍历旧版本的redis中所有的key,把数据取出来,插入到新的redis服务器中

  • rdb最大的问题就是不能实时持久化保存数据,在两次快照之间,实时的数据可能随着重启而丢失

AOF

aof以独立日志的方式记录每次写的命令,重启时在重新执行aof文件中的命令达到恢复数据的目的。aof主要作用是解决数据持久化的实时性问题,是目前redis持久化的主流方式。

使用AOF

开启aof功能需要在配置文件中设置:appendonly yes默认不开启。当开启aof后,rdb就不生效;启动以后不再读取rdb内容。aof文件名通过appendfilename配置文件中设置。aof文件所在位置和rdb文件所在的目录一样,默认/var/lib/redis(可配置)
image.png

向redis中添加key1,key2,key3

image.png
image.png
查看appendonly.aof文件
image.png

appendonly.aof文件记录了你的每一个操作命令,通过一些特殊符号作为分割符,来对命令的细节做出区分。aof文件的格式是文本格式,因为文本协议具备更好的兼容性,事先简单,具备可读性。

AOF的工作流程

image.png

aof-buf缓冲区

引入aof机制,既写内存,有写硬盘,速度还会很快吗?

  1. aof机制并不是直接让工作线程把数据写入硬盘,而是先写入内存的缓冲区aof_buf,积累一波后,再统一写入硬盘,降低了写硬盘的次数。写硬盘的时候,一次写入硬盘数据的多少,对于性能影响不是很大,但是写入硬盘的次数影响很大。
  2. 硬盘上读写数据,顺序读写的速度比较快,随机访问的速度比较慢。而aof每次把新的操作写入到原有文件的末尾,属于顺序写入。

把数据写入缓冲区,本质还是在内存中,当进程挂了或者主机掉电,缓冲区的数据会不会丢失?

会,缓冲区中没来得及写入硬盘的数据会丢。
缓冲区的刷新策略
image.png

  • always:每一步操作立刻同步到aof文件中,频率最高,数据可靠性最高,性能最低
  • everysec:每秒将缓冲区的数据写入aof文件,频率低一些,数据可靠性降低一些,性能提高一些,默认采用everysec策略image.png
  • no:由操作系统来控制什么时候写入aof文件,频率最低,数据可靠性最低,性能最高

重写机制(rewrite)

随着操作的增多,aof文件体积越来越大。redis启动的时候需要读取aof文件内容,这就会影响到redis启动时间。实际上redis启动的时候,只关注最终结果,并不关心aof文件中记录的中间过程,所以aof文件中有一些内容存在冗余。如下所示:
image.png
因此redis就引入了“重写机制”,对aof文件进行整理操作,剔除其中的冗余操作,并且合并一些操作,达到给aof文件瘦身的效果。

触发重写机制
  1. 手动触发:执行bgrewriteaof命令
  2. 自动触发:根据auto-aof-rewrite-min-sizeauto-aof-rewirte-percentage参数确定自动触发时机
    1. auto-aof-rewrite-min-size:表示触发重写时aof的最小文件大小,默认是64Mb
    2. auto-aof-rewrite-percentage:表示当前aof占用大小相比上次重写时增加的比例

image.png

AOF重写流程

image.png

序号2和4的过程

aof重写和rdb生成快照文件一样,都是通过多进程的方式。通过fork创建子进程,父进程负责接收请求,子进程负责针对aof文件进行重写。子进程只需要把当前内存中的数据,获取出来,以aof的格式写入到一个新的aof文件中。因为内存中的数据状态,就相当于把aof文件整理后的结果。此处子进程写数据的过程,类似于rdb生成一个镜像快照。只不过rdb是按照二进制的方式生成的,aof重写则是按照aof要求的文本格式生成的,都是把当前内存的所有数据状态给记录到文件中。

序号3.1的过程

子进程写新aof文件的同时,父进程仍然在不停的接收客服端新的请求,父进程会把这些请求先写入aof_buf缓冲区中,再刷新到原有的aof文件中。

序号3.2,5.1, 5.2, 5.3过程

在创建子进程的一瞬间,子进程继承了当前父进程的内存状态。因此子进程中的内存数据是父进程fork之前的状态,fork之后,新的请求,对内存造成的修改,是子进程不知道的。此时,父进程准备了一个aof_rewrite_buf缓冲区,专门放fork之后的数据。子进程把aof数据写完以后,会通过信号通知一下父进程,父进程再把aof_rewrite_buf缓冲区的内容也写到新的aof文件中,到这就可以用新的aof文件替换旧的aof文件。
什么是信号?
信号是linux的神经系统,是进程间通信的一种手段。信号能表达的信息有限,并不像socket可以传输任意数据,图中子进程向父进程发送一个信号,表示“我已经干完了”。
信号包含3部分

  • 信号源:哪个进程发送的
  • 信号类型:例如kill -9 表示给指定进程发送9号信号
  • 信号的处理函数:接收方接到这个信号触发的行为

如果在执行bgrewriteaof时,当前redis已经正在进行aof重写,会咋样?

此时,不会再次执行aof重写,直接返回。

如果在执行bgrewriteaof时,当前redis在生成rdb文件快照,会咋样?

此时aof重写操作会等待,等待rdb快照生成完毕之后,再执行aof重写

父进程fork完成后,子进程开始写入新的aof文件,随着时间推移,子进程写完新的文件后,让新的aof文件替换旧的aof文件。此时父进程仍然继续写入旧的aof文件是否有意义?

预防极端情况,例如服务器挂了,子进程的内存数据都会丢失,新的aof文件内容不完整,所以如果父进程不坚持写入旧的aof文件,重启旧无法保证数据的完整性。

启动时恢复数据

当redis启动时,会根据rdb和aof文件的内容,进行数据恢复,如下图所示:
image.png
如果开启aof,以aof为主,忽略rdb文件。因为aof中包含的数据比rdb更全。

混合持久化

aof是按照文本的方式写入文件的,导致后续加载的成本较高。因此redis引入“混合持久化”结合了rdb和aof特点,按照aof的方式,把每个请求/操作都记录到文件中,在触发aof重写之后,就会把当前内存的状态按照rdb的二进制格式写入到新的aof文件中,后续再进行的操作,仍然按照aof文本的方式追加到文件后头。
在redis.conf配置文件中开启混合持久化
image.png
示例:
image.png
打开appendonly.aof文件
image.png

相关文章:

刷新你对Redis持久化的认知

认识持久化 redis是一个内存数据库,数据存储到内存中。而内存的数据是不持久的,要想做到持久化,就需要让redis把数据存储到硬盘上。因此redis既要在内存上存储一份数据,还要在硬盘上存储一份数据。这样这两份数据在理论上是完全相…...

Greenplum-最佳实践小结

注:本文翻译自https://docs.vmware.com/en/VMware-Greenplum/7/greenplum-database/best_practices-logfiles.html 数据模型 Greenplum数据库是一个分析型MPP无共享数据库。该模型与高度规范化/事务性的SMP数据库明显不同。Greenplum数据库使用适合MPP分析处理的非…...

从Gamma空间改为Linear空间会导致性能下降吗

1)从Gamma空间改为Linear空间会导致性能下降吗 2)如何处理没有使用Unity Ads却收到了GooglePlay平台的警告 3)C#端如何处理xLua在执行DoString时候死循环 4)Texture2DArray相关 这是第350篇UWA技术知识分享的推送,精选…...

双轨制的发展,弊端和前景

双轨制是一种经济体制,指两种不同的规则或机制并行运行,以适应不同的市场或客户需求。双轨制最早出现在中国的改革开放中,是从计划经济向市场经济过渡的一种渐进式改革方式。 双轨制的发展可以分为三个阶段: 第一阶段(…...

生成对抗网络(GAN):在图像生成和修复中的应用

文章目录 什么是生成对抗网络(GAN)?GAN在图像生成中的应用图像生成风格迁移 GAN在图像修复中的应用图像修复 拓展应用领域总结 🎉欢迎来到AIGC人工智能专栏~生成对抗网络(GAN):在图像生成和修复…...

扬杰科技携手企企通,召开SRM采购供应链协同系统项目启动会

近日,中国功率半导体领先企业扬州扬杰电子科技股份有限公司(以下简称“扬杰科技”)与企企通召开SRM采购供应链协同系统项目启动会,双方项目团队成员一同出席本次会议。 会上,双方就扬杰科技采购供应链管理平台项目的目…...

AtCoder Beginner Contest 318

目录 A - Full Moon B - Overlapping sheets C - Blue Spring D - General Weighted Max Matching E - Sandwiches F - Octopus A - Full Moon #include<bits/stdc.h> using namespace std; const int N1e65; typedef long long ll ; const int maxv4e65; typedef …...

《Python魔法大冒险》003 两个神奇的魔法工具

魔法师:小鱼,要开始编写魔法般的Python程序,我们首先需要两个神奇的工具:Python解释器和代码编辑器。 小鱼:这两个工具是做什么的? 魔法师:你可以把Python解释器看作是一个魔法棒,只要你向它说出正确的咒语,它就会为你施展魔法。 小鱼:那这个解释器和我之前用的电…...

每日一题-动态规划(从不同类型的物品中各挑选一个,使得最后花费总和等于1000)

四种类型的物品&#xff0c;每一种类型物品数量都是n&#xff0c;先要从每种类型的物品中挑选一件&#xff0c;使得最后花费总和等于1000 暴力做法10000^4 看到花费总和是1000&#xff0c;很小且固定的数字&#xff0c;肯定有玄机&#xff0c;从这里想应该是用dp&#xff0c;不…...

2023-9-3 试除法判定质数

题目链接&#xff1a;试除法判定质数 #include <iostream>using namespace std;bool is_prime(int n) {if(n < 2) return false;for(int i 2; i < n / i; i){if(n % i 0) return false;}return true; }int main() {int n;cin >> n;while(n--){int x;cin &g…...

【Apollo学习笔记】——规划模块TASK之RULE_BASED_STOP_DECIDER

文章目录 前言RULE_BASED_STOP_DECIDER相关配置RULE_BASED_STOP_DECIDER总体流程StopOnSidePassCheckClearDoneCheckSidePassStopIsPerceptionBlockedIsClearToChangeLaneCheckSidePassStopBuildStopDecisionELSE:涉及到的一些其他函数NormalizeAngleSelfRotate CheckLaneChang…...

【SpringBoot】最基础的项目架构(SpringBoot+Mybatis-plus+lombok+knife4j+hutool)

汝之观览&#xff0c;吾之幸也&#xff01; 从本文开始讲下项目中用到的一些框架和技术&#xff0c;最基本的框架使用的是SpringBoot(2.5.10)Mybatis-plus(3.5.3.2)lombok(1.18.28)knife4j(3.0.3)hutool(5.8.21),可以做到代码自动生成&#xff0c;满足最基本的增删查改。 一、新…...

RNN 单元:分析 GRU 方程与 LSTM,以及何时选择 RNN 而不是变压器

一、说明 深度学习往往感觉像是在雪山上找到自己的道路。拥有坚实的原则会让你对做出决定更有信心。我们都去过那里 在上一篇文章中&#xff0c;我们彻底介绍并检查了 LSTM 单元的各个方面。有人可能会争辩说&#xff0c;RNN方法已经过时了&#xff0c;研究它们是没有意义的。的…...

Linux音频了解

ALPHA I.MX6U 开发板支持音频&#xff0c;板上搭载了音频编解码芯片 WM8960&#xff0c;支持播放以及录音功能&#xff01; 本章将会讨论如下主题内容。 ⚫ Linux 下 ALSA 框架概述&#xff1b; ⚫ alsa-lib 库介绍&#xff1b; ⚫ alsa-lib 库移植&#xff1b; ⚫ alsa-l…...

精心整理了优秀的GitHub开源项目,包含前端、后端、AI人工智能、游戏、黑客工具、网络工具、AI医疗等等,空闲的时候方便看看提高自己的视野

精心整理了优秀的GitHub开源项目&#xff0c;包含前端、后端、AI人工智能、游戏、黑客工具、网络工具、AI医疗等等&#xff0c;空闲的时候方便看看提高自己的视野。 刚开源就变成新星的 igl&#xff0c;不仅获得了 2k star&#xff0c;也能提高你开发游戏的效率&#xff0c;摆…...

Leetcode54螺旋矩阵

思路&#xff1a;用set记录走过的地方&#xff0c;记下走的方向&#xff0c;根据方向碰壁变换 class Solution:def spiralOrder(self, matrix: list[list[int]]) -> list[int]:max_rows len(matrix)max_cols len(matrix[0])block_nums max_cols * max_rowscount 1i 0j…...

element-plus 表格-方法、事件、属性的使用

记录element-plus 表格的使用。方法、事件、属性的使用。因为是vue3的方式用到了const install getCurrentInstance();才能获取表格的相关信息 没解决怎么获取选中的行的行号&#xff0c;采用自己记的方式实习的。 利用row-class-name"setRowClass"实现样式的简单…...

NVME Linux的查询命令-继续更新

NVME Linux的查询命令 查看NVMe设备 # nvme list 查看nvme controller 支持的一些特性 # nvme id-ctrl /dev/nvme0 查看设备smart log信息 # nvme smart-log /dev/nvme0 查看设备error 信息 # nvme error-log /dev/nvme0 设备的所有命名空间 # nvme list-ns /dev/nvmeX 检…...

pyqt5-自定义文本域1

快捷键支持&#xff1a; CTRL鼠标滚轮实现字体大小调整 支持复制当前行 剪切当前行 # 多行文本框 class TextEdit(QTextEdit):def __init__(self, parentNone):super().__init__(parent)self.setStyleSheet("background-color: #262626;color: #d0d0d0;")self.setFon…...

Go实现LogCollect:海量日志收集系统【上篇——LogAgent实现】

Go实现LogCollect&#xff1a;海量日志收集系统【上篇——LogAgent实现】 下篇&#xff1a;Go实现LogCollect&#xff1a;海量日志收集系统【下篇——开发LogTransfer】 项目架构图&#xff1a; 0 项目背景与方案选择 背景 当公司发展的越来越大&#xff0c;业务越来越复杂…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

rknn toolkit2搭建和推理

安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 &#xff0c;不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源&#xff08;最常用&#xff09; conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

C++--string的模拟实现

一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现&#xff0c;其目的是加强对string的底层了解&#xff0c;以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量&#xff0c;…...