2023.1.15 关于 Redis 持久化 RDB 策略详解

目录

Redis 持久化

                Redis 实现持久化的两大策略

RDB 策略

手动触发

                save 命令

                bgsave 命令

                        bgsave 命令执行流程

自动触发

rdb 文件

实例演示一

实例演示二

实例演示三

实例演示四

RDB 策略的优缺点


Redis 持久化

  • 什么是持久化?

回答:

  • 将数据存储在硬盘上——> 持久
  • 将数据存储在内存上 ——> 不持久
  • 所以持久化的判断标准为 重启进程 或 重启主机 后,数据是否存在!

  • Redis 是一个内存数据库,即将数据存储在内存中
  • 但内存中的数据是不持久的,要想能够做到持久,就需要让 Redis 将数据存储到硬盘上
  • Redis 相比于 MySQL 关系型数据库,其最明显的特优势为 效率高、速度快
  • 所以为了保证速度快,Redis 的数据肯定还是得存储在内存中
  • 但是为了持久化,Redis 的数据还得想办法存储在硬盘上
  • 随之 Redis 决定在 内存 中存储数据的同时 硬盘 上也进行数据的存储

通俗理解:

  • 当插入一个新数据时,将该数据同时写入到内存和硬盘
  • 当查询某个数据时,直接从内存读取
  • 硬盘上的数据只是在 Redis 重启的时候,用来恢复内存中的数据的

代价:

  • 消耗了更多的空间,即同一份数据存储了两遍
  • 但是由于硬盘比较便宜,因此这样的开销并不会带来多大的成本

注意点一:

  • 内存上 和 硬盘上 的两份数据,理论上是完全相同的
  • 但实际上可能存在一些小差异,这完全取决于我们如何针对数据进行持久化

注意点二:

  • 说是两边都写,但实际上具体怎么写硬盘还有着不同的策略
  • 但是可以保证的是 整体的效率还是足够高的

Redis 实现持久化的两大策略

  • RDB ——> Redis DataBase(定期备份)
  • AOF ——> Append Only File(实时备份)

注意:

  • Redis 服务器配置文件默认开启 RDB(定期备份)

RDB 策略

  • RDB 定期将 Redis 内存中的所有数据都给写入到硬盘中,即生产一个 "快照"

通俗理解:

  • Redis 给当前在内存中存储的所有数据拍个照片,生成一个 rdb 文件,并将其存储在硬盘中
  • 如果后续 Redis 服务器一旦重启了(内存数据就没了),就可以根据刚才的 "快照" 将内存中的数据给恢复回来

  • RDB 定期备份具有两种触发方式,分别为 手动触发、自动触发

手动触发

  • 程序员通过 Redis 客户端执行特定的命令,以此触发 "快照" 生成

save 命令

  • 执行 save 命令时,Redis 会全力以赴的生成 "快照" ,此时就有可能阻塞 Redis 的其他客户端命令

注意:

  • 使用改命令时,可能会导致类似于 keys * 的后果
  • 所以一般不建议使用 save 命令

bgsave 命令

  • bg ——> backgroud(后面)即不会影响 Reids 服务器处理其他客户端的请求和命令

问题:

  • Redis 时如何做到的呢? 是否弄了个多线程来执行该命令? 

回答:

  • 此处 Redis 使用 多进程 的方式来完成的并发编程,从而完成的 bgsave 命令的实现

bgsave 命令执行流程


第一步

  • 判定当前是否已经存在其他正在工作的子进程

  • 比如现在已经有一个子进程正在执行 bgsave,此时将直接把当前的 bgsave 返回


第二步

  • 如果没有其他的工作子进程,就通过 fork 这样的系统调用来创建一个子进程

重点理解:

  • Java 进行并发编程时,主要通过 多线程 的方式
  • fork 是 linux 系统提供的一个创建子进程的 api (系统调用)
  • fork 会直接将当前的进程(父进程)复制一份,作为子进程
  • 复制完成之后,父子进程就变为两个独立进程,即各自执行各自的
  • 此处所说的复制操作 会复制 pcb 虚拟地址空间(内存中的数据)、文件描述符表等
  • 本来 Redis 服务器中有若干变量,即保存了一些键值对数据
  • 随着 fork 的进行,子进程的这个内存里也会存在和刚才父进程中一模一样的变量(键值对数据)
  • 因此子进程 内存中的数据 和 父进程 内存中的数据 相同
  • 接下来便安排子进程去执行 持久化 操作,也就相当于把父进程本体这里的内存数据给持久化了

注意:

  • 正因为 父进程文件描述符表 也被 子进程 给复制了
  • 所以当父进程打开了一个文件 且  fork 了之后,子进程也是可以同样使用这个文件的
  • 因此也就导致了子进程持久化写入的那个文件和父进程本来要写的文件是同一个

问题:

  • 如果当前 Redis 服务器中存储的数据特别多,内存消耗特别大(比如 100G)
  • 此时进行上述的复制操作是否会有很大的内存开销?

回答:

  • 此处的性能开销其实挺小的
  • fork 在进行内存拷贝时,不是无脑的直接将所有数据均拷贝一遍,而是以 写时拷贝 的机制来完成的

  • 如果子进程里的这个内存数据和父进程的内存数据完全一致,此时就不会触发真正的拷贝动作,而是子父进程共用同一份内存数据
  • 但是子父进程的内存空间各自独立
  • 一旦某个内存数据做了修改,此时便会立即触发真正的 物理内存 上的数据拷贝

小总结:

  • 在进行执行 bgsave 命令时,绝大部分的内存数据是不需要改变的
  • 整体来说这个过程执行还挺快的
  • 因为短时间内,父进程中不会有大批的内存数据的变化
  • 因此子进程 写时拷贝 并不会触发很多次,也就保证了整体的拷贝时间是可控的、高效的

第三步

  • 子进程负责进行 写文件,生成快照的过程
  • 父进程继续接收客户端的请求,继续正常提供服务

第四步

  • 子进程完成整体的持久化过程之后,就会通知父进程,干完了,父进程就会更新一些统计信息
  • 执行至此 子进程 便可以结束并销毁了!

 自动触发

自动触发 Redis 生成快照的操作有多种方式:

  1. 通过刚才配置文件中  save 执行 M 时间内,修改 N 次
  2. 通过 shutdown 命令(redis 里的一个命令)关闭 redis 服务器,也会触发(正常关闭)
  3. 在 Redis 进行主从复制时,主节点也会自动生成 rdb 快照,然后将 rdb 快照文件内容传输给从节点

注意:

  • 但在实际开发中,更害怕的是出现异常情况!

  • Rdis 的配置文件中关于方式一如下图所示

方式一的触发条件:(默认值)

  • 900 秒内 至少 1 次 key 的修改
  • 300 秒内 至少 10 次 key 的修改
  • 60 秒内 至少 10000 次 key 的修改

注意:

  • 虽然此处的数值可以自由修改配置
  • 但是,此处修改上述数据的时候,要有一个基本的原则

原则:

  • 生成一次 rdb "快照",是高成本的操作,所以不能让该操作执行的太频繁!
  • 在默认配置中,生成两次 rdb "快照" 之间的间隔最少也为 60秒

小总结:

  • 正因为 rdb "快照"生成的不能太频繁
  • 因此也就导致 "快照" 里的数据和当前实时的数据情况可能存在一定偏差

实例理解

rdb 文件

  • Redis 生成的 rdb 文件存放在 Redis 的工作目录中 Redis 配置文件可自行设置)


  • RDB 机制生成的镜像文件为二进制的文件
  • 即将内存中的数据以压缩的形式保存到这个二进制文件中
  • 而 压缩 需要消耗一定的 CPU 资源,但是能节省空间

注意点一:

  • Redis 服务器重新启动,就会尝试加载这个 rdb 文件
  • 如果发现格式错误,就可能会加载数据失败!
  • rdb 文件,在我们不主动修改它的前提下,也可能会存在一些意外情况
  • 即 一旦通过一些操作(比如网络传输)引起 rdb 文件被破坏,此时 Redis 服务器就无法启动

ps:

  • redis 提供了 rdb 文件的检查工具 ——> redis-check-rdb*

注意点二:

  • rdb 持久化操作可触发多次
  • 当执行生成 rdb 镜像操作的时候
  • 此时就会把要生成的快照数据,先保存到一个临时文件中
  • 当这个快照生成完毕之后,再删除之前的 rdb 文件,把新生成的 rdb 文件名字改成刚才的 dump.rdb
  • 因为从始至终,rdb 文件有且仅有一个

  • bgsave 操作流程是创建子进程,子进程完成持久化操作
  • 持久化会把数据写入到新的文件中,然后使用新的文件替换旧的文件

注意:

  • 因为 持久化速度太快了(数据少),我们难以观察到 子进程
  • 但是 使用新文件替换旧文件 这个是可以观察到的

实例理解

  • 使用 linux 的 stat 命令,查看文件的 inode 编号


补充点一:Linux 文件系统

  • 文件系统典型的组织方式(ext4)主要把整个文件系统分成了三个大的部分:
  1. 超级块(放的是一些管理信息)
  2. inode 区(存放 inode 节点 每个文件都会分配一个 inode 数据结构,包含了文件的各种元数据)
  3. block 区(存放文件的数据内容)

补充点二:

  • 直接使用 save 命令不会触发 子进程 和 文件替换 逻辑
  • 则直接在当前进程中,往刚才的同一个文件中写入数据

实例演示一

  • 根据该实例演示,我们来仔细观察新 rdb 文件的生成

1、Redis 未设置 任何键值对的 dump.rdb 文件


2、向 Redis 设置 3个键值对


3、再次打开 dump.rdb 文件,此时并未发生任何变化

注意:

  • rdb 文件中的数据,不是你这边插入了数据,就会立即更新的

RDB 机制的触发时机:

  • 手动触发(save、bgsave)
  • 自动触发

原因:

  • 正因为刚才插入 3个键值对,没有运行手动触发的命令,也达不到自动触发的条件
  • 因此 dump.rdb 文件并未发生改变 

4、此时我们手动执行 bgsave 命令触发一次生成快照

  • 由于此处的数据比较少,执行 bgsave 命令后 一瞬间便完成了

5、立即查看应该就是有结果的

  • 此处我们可以看到 dump.rdb 中已经发生了改变!

注意:

  • 如果 Redis 中的数据多,执行 bgsave 命令就可能需要消耗一定的时间
  • 立即查看不一定就是生成完毕了

6、将现在正在运行的 Redis 服务器重启,看是否能恢复内存之前的状态

  • 由上图可知,Redis 服务器在重新启动时,加载了 rdb 文件的内容,恢复了内存之前的状态

7、向 Redis 中设置新的键值对,但不手动执行 bgsave 命令直接重启 Redis 服务器

  • 刚才没有执行 bgsave 命令,但是这个 key4 居然在重启之后仍然存在!
  • 自动触发 ——> 方式二

8、打开并查看 dump.db 文件

实例演示二

  • 当 Redis 服务器出现异常情况时会导致什么后果?
  • 即 非正常关闭 Redis 服务器

1、此处我们使用 kill -9 命令来模拟异常情况的出现

  • 由上图可知,在 Redis 重启之后,key5 丢失!

2、打开并查看 dump.db 文件


总结:

  • 如果是通过正常流程重新启动 Redis 服务器(kill 命令),此时 Redis 服务器会在退出时,自动触发生成 rdb 操作
  • 但是 如果是异常重启(kill -9 命令 或者 服务器掉电),此时 Redis 服务器便来不及生成 rdb,即内存中尚未保存到快照中的数据,就会随着重启而丢失

实例演示三

  • 此处我们演示观察 自动触发(通过配置)生成 rdb 快照
  • 即在 Redis 配置文件中,设置让 Redis 每隔多长时间并产生多少次修改 就触发

1、执行 FLUSHALL 命令,清除前面测试的键值对(执行 FLUSHALL 也会清空 rdb 文件)


2、修改配置文件


3、重启服务器,并插入 2个键值对

注意:

  • redis 来说,修改配置文件之后,一定要重启服务器,才能生效!

4、等待 60秒,查看 dump.rdb 文件

  • 由上图可以,redis 成功生成 rdb "快照"

实例演示四

  • 如果将 rdb 文件故意改坏会导致什么后果?

1、手动的将 rdb 文件内容改坏


2、通过 kill -9 命令的方式重新启动 Redis 服务器

  • 由上图可知,Redis 服务器启动失败!

注意:

  • 如果仅通过 kill 命令的方式重启,就会在 Redis 服务器退出时,重新生成 rdb 快照
  • 此时新生成的 rdb 文件便会将刚改坏了的旧文件给替换掉
  • 因此无法观察到效果!

3、查看 Redis 的日志


具体解释:

  • rdb 文件为二进制文件
  • 上述操作所导致的后果为 直接改坏的 rdb 文件交给 Redis 去使用 
  • 此处得到的结果是不可预期的
  • 可能 Redis 服务器能启动,但是得到的数据可能正确也可能也有问题
  • 也有可能 Redis 服务器直接启动失败(如上述情况所示)

补充:

  • 但 Redis 提供了 rdb 文件的检查工具 ——> redis-check-rdb
  • 所以我们可以在启动 Redis 服务器之前,先通过 检查工具,检查 rdb 文件格式是否符合要求
  • 运行的时候,加入 rdb 文件作为命令行参数 ——> redis-check-rdb dump.rdb
  • 此时就是以检查工具的方式来运行,不会真的启动 redis 服务器

RDB 策略的优缺点

  • RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照,非常适用于备份、全量复制等场景,比如每 6小时执行 bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中
  • Redis 加载 RDB 恢复数据远远快于 AOF 方式
  • RDB 方式数据没办法做到实时持久化 或 秒级持久化,因为 bgsave 每次运行都要执行 fork 创建子进程,属于重量级操作,频繁执行成本过高
  • RDB 文件使用特定二进制格式保存,Redis 版本演变过程中有多个 RDB 版本,兼容性可能有风险

注意:

  • RDB 使用二进制的方式来组织数据,直接把主句读取到内存中,按照字节的格式取出来,并放到 结构体 / 对象 中即可
  • AOF 是通过文本的方式来组织数据的,则需要进行一系列的字符串切分操作

补充:

  • 一个老版本 Redis 的 rdb 文件,放到新版本 Reids 中不一定能识别的了
  • 在一般的实际工作当中,Redis 版本都是统一的
  • 如果确实有一些升级版本的需求,即遇到了不兼容的问题
  • 就可以通过写一个程序的方式,直接遍历旧 Redis 服务器中的所有 key,把数据取出来,插入到新 Reids 服务器中即可

总结:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/325076.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

纯c实现顺序表 数据结构大全

我们已经知道数组是连续的内存地址,顺序表是由数组为基础的一种数据结构,拥有比数组更多的功能,在概念上属于线性结构,跟链表不同的是,顺序表在物理结构上也是线性的 什么是数据结构? 当我们想要使⽤⼤量使…

【教3妹学编程-算法题】3006. 找出数组中的美丽下标 I

3妹:呜呜,烦死了, 脸上长了一个痘 2哥 : 不要在意这些细节嘛,不用管它,过两天自然不就好了。 3妹:切,你不懂,影响这两天的心情哇。 2哥 : 我看你是不急着找工作了啊, 工作…

AI-基于Langchain-Chatchat和chatglm3-6b部署私有本地知识库

目录 参考概述部署安装环境准备原理和流程图一键启动启动WebAPI 服务启动WebUI服务 Docker部署知识库管理常见问题本地知识库怎么微调?回答不准确 参考 手把手教你搭建本地知识库问答AI机器人 LangChain-Chatchat:基于LangChain和ChatGLM2-6B构建本地离…

【小笔记】时序数据分类算法最新小结

2024.1.15 最近基于时序数据训练分类算法,对其进行了一番了解,主要围绕以下几点: 时序数据算法有哪些细分类?时序数据分类算法经典模型?当下时序分类算法模型强baseline?有没有现成的工具? 1…

Python - 深夜数据结构与算法之 位运算

目录 一.引言 二.位运算简介 1.二进制与十进制 2.左/右移 3.位运算 4.异或 XOR 5.指定位置的位运算 6.实战要点 三.经典算法实战 1.Number-1-of-bits [191] 2.Power-Of-Two [231] 3.Reverse-2-Bits [190] 4.N-Queens [51] 四.总结 一.引言 通常情况下我们计数采…

RequestResponse

1.Request 请求 作用:使用Request对象来获取请求数据 1.Request获取请求数据的方法 2.通用方式获取请求参数 3.POST请求参数中文乱码解决 4.请求转发 概念: 一种在服务器内部的资源跳转方式 2.Response 响应 作用:使用response对象设置响应数据 1.Response设置响应数据功能 …

【Emgu.CV教程】5.3、几何变换之金字塔变换

这一段文字描述来自百度百科: 图像金字塔是图像多尺度表达的一种,是一种以多分辨率来解释图像的有效但概念简单的结构。一幅图像的图像金字塔是一系列以金字塔形状(自下而上)逐步降低,且来源于同一张原始图的图像分辨率…

OpenCV-25sobel算子(索贝尔算子)

前面所提到的滤波都是用于降噪的,去掉噪声,而算子是用来找边界,来识别图像的边缘。 一、概念 边缘是像素值发生跃迁的值,是图像的显著特点之一,在图像特征提取,对象检测,模式识别等方面都有重…

数据结构与算法教程,数据结构C语言版教程!(第四部分、字符串,数据结构中的串存储结构)二

第四部分、字符串,数据结构中的串存储结构 串存储结构,也就是存储字符串的数据结构。 很明显,字符串之间的逻辑关系也是“一对一”,用线性表的思维不难想出,串存储结构也有顺序存储和链式存储。 提到字符串&#xff…

Java 日志体系泣血总结

目录 一. 前言 二. Log 日志体系 2.1. 背景/发展史 2.2. 关系/依赖 2.2.1. JCL(Jakarta Commons Logging) 2.2.2. SLF4J 2.2.3. SLF4J 的适配 2.2.4. Spring 统一输出 三. 总结 一. 前言 本文的目的是搞清楚 Java 中各种日志 Log 之间是怎样的关…

spring boot mybatis-plus dynamic-datasource 配置文件 相关依赖环境配置

spring boot mybatis-plus dynamic-datasource 配置文件 相关依赖环境配置 ##yaml配置 server:port: 8866servlet:context-path: /yymtomcat:max-threads: 300connection-timeout: 57000max-connections: 500connection-timeout: 57000 spring:datasource:dynamic:primary: m…

MyBatis 查询数据库

一. MyBatis 框架的搭建 本篇所用sql 表: drop table if exists userinfo; create table userinfo(id int primary key auto_increment,username varchar(100) not null,password varchar(32) not null,photo varchar(500) default ,createtime timestamp default current_tim…

SpringBoot 全局异常统一处理:BindException(绑定异常)

概述 在Spring Boot应用中,数据绑定是一个至关重要的环节,它负责将HTTP请求中的参数映射到控制器方法的入参对象上。在这个过程中如果遇到任何问题,如参数缺失、类型不匹配或验证失败等,Spring MVC将会抛出一个org.springframewo…

Hive 数据迁移

一、需求 同步集团的数据到断直连环境。 二、思路 三、同步数据(方案) 1、环境:断直连模拟环境 2、操作机器:ETL 机器 XX.14.36.216 3、工作路径:cd /usr/local/fqlhadoop/hadoop/bin 4、执行命令: 命令…

python 元组的详细用法

当前版本: Python 3.8.4 文章目录如下 1. 介绍元组 2. 定义元组 3. 访问元组 4. 查询元组 1. 介绍元组 元组(Tuple)是一个有序的、不可变的数据序列。它可以包含各种类型的数据,例如数字、字符串、列表等。元组使用圆括号()来…

书生·浦语大模型实战营第四节课笔记及作业

XTuner 大模型单卡低成本微调实战 1 Finetune简介 大语言模型LLM是在海量的文本内容基础上,以无监督或半监督方式进行训练的。海量的文本内容赋予了大模型各种各样的行业知识。但是如果直接把大模型的知识用于生产实践,会发现回答不大满意。微调的目的…

【RL】(task1)绪论、马尔科夫过程、动态规划、DQN(更新中)

note 文章目录 note一、马尔科夫过程二、动态规划DQN算法时间安排Reference 一、马尔科夫过程 递归结构形式的贝尔曼方程计算给定状态下的预期回报,这样的方式使得用逐步迭代的方法就能逼近真实的状态/行动值。 有了Bellman equation就可以计算价值函数了马尔科夫过…

微服务架构设计核心理论:掌握微服务设计精髓

文章目录 一、微服务与服务治理1、概述2、Two Pizza原则和微服务团队3、主链路规划4、服务治理和微服务生命周期5、微服务架构的网络层搭建6、微服务架构的部署结构7、面试题 二、配置中心1、为什么要配置中心2、配置中心高可用思考 三、服务监控1、业务埋点的技术选型2、用户行…

Burp Suite如何拦截站点请求

Burp Suite是一款强大的Web渗透测试工具,可以用于拦截、修改和分析Web应用程序的请求和响应。要使用Burp Suite拦截站点请求有两个方案。我会倾向选用方案二,因为它不会影响本地电脑代理配置。 1. 方案一 安装Burp Suite:首先,您…

【C语言】ipoib驱动 - ipoib_cm_post_receive_nonsrq_rss函数

一、ipoib_cm_post_receive_nonsrq_rss函数定义 static int ipoib_cm_post_receive_nonsrq_rss(struct net_device *dev,struct ipoib_cm_rx *rx, int id) {struct ipoib_dev_priv *priv ipoib_priv(dev);struct ipoib_recv_ring *recv_ring priv->recv_ring rx->ind…
最新文章