深入了解Redis——持久化

一,Redis持久化

Redis持久化即将内存中的数据持久化到磁盘中,在下一次重启后还能进行使用,Redis持久化分为RDBAOF两种,我们接下来分别介绍RDB和AOF的内部原理和区别

RDB

Redis运行时会将当前的内存快照存入至磁盘中,Redis重新启动后会将快照以二进制的形式给加载进入内存中,其中rdbSaverdbLoad函数至关重要

image

什么时候会触发RDB?

  • Redis停机时会触发
  • 使用命令 save m n
  • 主从同步执行全量复制
  • debug reload命令重新加载Redis

保存

在RDB文件期间,主进程会被阻塞,直至保存完成,其中也分为了两种不同的保存方式SAVEBGSAVE

def SAVE():rdbSave()def BGSAVE():pid = fork()if pid == 0:# 子进程保存 RDBrdbSave()elif pid > 0:handle_request()else:# pid ==-1# 处理 fork 错误handle_fork_error()
  • SAVE: 该方法会阻塞Redis主进程,此时不会响应用户请求,直至保存完成位置

image

  • **BGSAVE:**该方法不会阻塞Redis主进程,主线程会查看是否已经fork了一个子线程,如果fork则返回,否则fork一个子进程采用CopyOnWrite机制将当前的快照存入磁盘中

image

SAVE,BGSAVE,BGREWRITEAOF能同时执行吗

  • 对于SAVE来说:

    由于SAVE是阻塞当前主进程的,所以此时此刻不管是用户命令还是BGSAVEBGREWRITEAOF都无法执行,在执行SAVE指令前会检查BGSAVE是否在执行,如果在执行则不能进行SAVE

  • 对于BGSAVE来说:

    **BGSAVE与BGSAVE:**通过上述代码我们可以知道,当BGSAVE正在执行时,会检查子进程是否fork如果fork了子进程则直接返回,所以是不能同时执行的

    **BGSAVE与BGREWRITEAOF:**BGSAVE正在执行时,BGREWRITEAOF会延迟收到指令直至BGSAVE执行完毕。如果BGREWRITEAOF正在执行,BGSAVE会直接返回报错,无法同时执行。

载入

Redis服务器启动时,就会进行rdbLoad函数,此时在载入期间每载入1000条数据就会处理一次当前的用户命令,当然这里的用户命令只能时订阅与发布功能相关的,其他的命令都会统一拒绝。

在载入的时候会优先选择AOF,如果没有设置AOF才会使用RDB

RDB文件结构

一个RDB的文件结构如下所示:

image

  • **REDIS:**该字符标识着RDB文件的开始,相当于魔数
  • RDB-VERSION(四字节): 记录了当前文件RDB的版本号,读取的时候要使用对于版本号的方法读取
  • DB-DATA: 该部分会在RDB文件中出现多次,保存着一个服务器上非空数据库的所有数据
  • SELECT-DB: 代表着该键值对所属的数据库号码,读入RDB文件时,会根据该号码不断切换数据库
  • KEY-VALUE-PAIRS: 代表着一个键值对的数据,每个键值对的数据会用以下结构来进行保存

image

OPTIONAL-EXPIRE-TIME: 这个代表着当前的键值对过期时间,如果没有则为null

TYPE-OF-VALUE: 代表着该键值对以什么样的类型进行存储,会根据不同的类型来进行VALUE的读取(这个地方内容较多,暂不介绍)

KEY: 存储着当前的键

VALUE: 存储着当前键保存的值

  • EOF: 标志数据库内容的结尾,并不是文件的末尾
  • CHECK-SUM: 文件内容校验和,读取时会对其进行文件内容的校验,如果为0则代表关闭了校验和功能

AOF

AOF以协议文本的方式,将所有对数据库写入的命令记录至AOF文件中,以此达到记录数据库状态的目的

image

AOF运行阶段

同步命令至AOF文件分为三个阶段:

命令传播: 将当前的Redis执行完的命令,以命令请求,命令参数,命令参数个数的形式传输给AOF程序

image

缓存追加: 将命令数据接收,并转换为网络通讯的协议方式,将内容追加至AOF缓存当中。

文件写入和保存: 将缓存的内容根据设定的AOF条件写入至AOF文件末尾,此时会调用fsync函数或者fdatasync函数来将写入内容保存至磁盘中

此时会调用aof.c/flushAppendOnlyFile函数来执行以下两个工作:

WRITE(主进程阻塞):根据写入条件,将当前aofBuf的内容写入至AOF文件末尾,这个是写入至文件缓冲区的,写入之后直接返回,如果此时发生宕机,此时写入的内容将丢失

SAVE(主进程看情况阻塞) :根据保存条件,将当前的AOF文件缓存内容保存至磁盘中。采用fsync或fdatasync。

fysnc和fdatasync

参考文献

**fsync:**他会刷新文件的所有修改的核心数据包括文件关联的元数据,再刷新至磁盘中时,他会一直阻塞直至刷新完成

**fdatasync:**他和fsync类似,但是他不会刷新所有的文件元数据,会根据需要来进行刷新

AOF保存模式

Redis 目前支持三种 AOF 保存模式,它们分别是:

AOF_FSYNC_NO :不保存

在不保存的情况下,整个Redis执行期间WRITE会被执行但是不会执行SAVE命令,只有以下几种可能会执行SAVE命令

  • Redis被关闭
  • AOF被关闭
  • 系统的写缓存被刷

这三种情况下的SAVE都会导致主进程阻塞

AOF_FSYNC_EVERYSEC :每一秒钟保存一次

SAVE在原则上会一秒钟执行一次,且这个SAVE是由fork出来的子进程进行执行的,但是值得注意的是这个是原则上面的一秒钟,它是否是每次一秒调用和当前Redis所处的状态有关。

image
  • 子线程正在执行SAVE:

​ 如果执行SAVE时间小于2s:无需进行额外的write和save,程序执行返回

​ 如果执行SAVE时间超过2s:程序执行追加write,但不执行新的save。此时的write必须等待save执行完毕才能进行,所以主线程也会阻塞

  • 子线程没有执行SAVE:

​ 如果上次执行SAVE距今不超过1s:程序执行write但不执行save

​ 如果上次执行SAVE时间距今超过1s:程序执行write和save

所以我们如果在上图的情况1宕机,那此时只会损失小于2s的数据,但是如果在情况发生宕机,此时write已经有2s没写入文件缓存并刷入磁盘,就会有2s的数据损失。所以说AOF_FSYNC_EVERTSEC只损失1s的数据是不准确的

AOF_FSYNC_ALWAYS :每执行一个命令保存一次

每次执行完一个命令都会执行一次wirte指令和save指令,但是save是Redis主进程执行的所以主进程会阻塞

三种保存模式的对比图

image

image

AOF文件读取与数据还原

AOF文件内容如下

*2$6SELECT$10*3$3SET$3key$5value*8$5RPUSH$4list$11$12$13$14$15$1

我们可以看到在AOF文件内容中有一个SELECT 0 指令,该指令是为AOF文件指定要还原的数据库。

AOF文件的数据还原步骤如下:

① 开启一个伪客户端(fake cilent)

② 读取AOF的文件内容,并将其处理为命令,命令参数,参数个数该形式

③ 使伪客户端执行这些命令,直至所有命令执行完毕

这三步结束后,便会将AOF文件中的内容全部还原成数据库数据。在加载和还原期间只有订阅和发布功能能够使用,其他的都不能使用。

def READ_AND_LOAD_AOF():# 打开并读取 AOF 文件file = open(aof_file_name)while file.is_not_reach_eof():# 读入一条协议文本格式的 Redis 命令cmd_in_text = file.read_next_command_in_protocol_format()# 根据文本命令,查找命令函数,并创建参数和参数个数等对象cmd, argv, argc = text_to_command(cmd_in_text)# 执行命令execRedisCommand(cmd, argv, argc)# 关闭文件file.close()

AOF重写

对于一个Redis服务器来说,可能会接收几十万上千万的指令请求,如果此时将这些请求全部存入AOF文件,将会导致AOF文件不断庞大,对Redis和系统造成影响,于是为了将AOF文件进行压缩,便设计了AOF重写方法:AOF文件并不一定要写入所有的客户端指令只要保证前后状态一致即可,创建一个新的AOF文件替代原本的AOF文件,新AOF文件和原有的AOF文件对于数据库状态完全一样

实现原理:

对于下列命令集合我们可以发现,我们一开始创建了一个list[1,2,3,4],然后经过三次操作将其变为了list[1,2,3],那其实这四段命令我们可以直接压缩成一行也就是RPUSH list 1 2 3,这样即使的结果和前面的四次操作完全一致。

RPUSH list 1 2 3 4	 // [1, 2, 3, 4]
RPOP list			// [1, 2, 3]
LPOP list			// [2, 3]
LPUSH list 1		// [1, 2, 3]
def AOF_REWRITE(tmp_tile_name):f = create(tmp_tile_name)# 遍历所有数据库for db in redisServer.db:# 如果数据库为空,那么跳过这个数据库if db.is_empty(): continue# 写入 SELECT 命令,用于切换数据库f.write_command("SELECT " + db.number)# 遍历所有键for key in db:# 如果键带有过期时间,并且已经过期,那么跳过这个键if key.have_expire_time() and key.is_expired(): continueif key.type == String:# 用 SET key value 命令来保存字符串键value = get_value_from_string(key)f.write_command("SET " + key + value)elif key.type == List:# 用 RPUSH key item1 item2 ... itemN 命令来保存列表键item1, item2, ..., itemN = get_item_from_list(key)f.write_command("RPUSH " + key + item1 + item2 + ... + itemN)elif key.type == Set:# 用 SADD key member1 member2 ... memberN 命令来保存集合键member1, member2, ..., memberN = get_member_from_set(key)f.write_command("SADD " + key + member1 + member2 + ... + memberN)elif key.type == Hash:# 用 HMSET key field1 value1 field2 value2 ... fieldN valueN 命令来保存哈希键field1, value1, field2, value2, ..., fieldN, valueN =\get_field_and_value_from_hash(key)f.write_command("HMSET " + key + field1 + value1 + field2 + value2 +\... + fieldN + valueN)elif key.type == SortedSet:# 用 ZADD key score1 member1 score2 member2 ... scoreN memberN# 命令来保存有序集键score1, member1, score2, member2, ..., scoreN, memberN = \get_score_and_member_from_sorted_set(key)f.write_command("ZADD " + key + score1 + member1 + score2 + member2 +\... + scoreN + memberN)else:raise_type_error()# 如果键带有过期时间,那么用 EXPIREAT key time 命令来保存键的过期时间if key.have_expire_time():f.write_command("EXPIREAT " + key + key.expire_time_in_unix_timestamp())# 关闭文件f.close()

从上面的代码我们可以总结出以下步骤:

  • 遍历数据库,如果数据库为空则跳过,否则进入进行key遍历
  • 对所有的key进行遍历,如果key过期了则跳过,否则直接根据类型获取key的值,然后通过set的方式将其写入AOF文件中
  • 如果key有过期时间则给其赋予过期时间
  • 关闭文件写入
后台AOF重写

通过上面的AOF重写我们可以得知AOF重写是阻塞的,Redis也为AOF重写fork了一个子进程进行重写的处理。

image

① 执行BGREWRITEAOF指令,父进程fork出一个子进程来进行AOF重写操作

② 同时创建aof_rewrite_buf来缓存在重写过程中,执行的新的命令,父进程会将执行的命令同时放入aof_rewrite_buf和aof_buf中,保证不管是重写失败还是重写过程中都不会发生丢失数据的情况。

③ 子进程根据aof_rewrite_buf将重写后的指令写入新的AOF文件中

④ 当前重写全部执行完成后向父进程发送一个通知

⑤ 父进程将新的AOF文件与旧的AOF文件替换,完成重写

重写的自动触发条件:

重写可以通过手动命令bgrewriteaof进行,也可以自动进行不过要符合以下条件

  • 没有BGSAVE在执行
  • 没有SAVE在执行
  • 没有BGREWRITEAOF在执行
  • 当前AOF文件大小大于aof_rewrite_min_size(重写触发最小值 默认1mb)
  • 比较当前AOF文件和最后一次AOF文件重写的大小之间的比例是否超过一倍(比如当前AOF文件是2MB,重写时的文件是1MB,此时就超过一倍了)

符合以上条件则会进行自动的AOF重写。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

./build/examples/openpose/openpose.bin在windows中调用

直接看这个更简单的方法:https://blog.csdn.net/weixin_45615730/article/details/137591825?spm1001.2014.3001.5501 问题描述: 在跑pifuhd,需要两个输入,一个图片,一个关键点json文件。这是人家给的例子&#xff0…

怎么开发一个预约小程序_一键预约新体验

预约小程序,让生活更便捷——轻松掌握未来,一键预约新体验 在快节奏的现代生活中,我们总是在不断地奔波,为了工作、为了生活,不停地忙碌着。然而,在这繁忙的生活中,我们是否曾想过如何更加高效…

邮件群发提高成功率的技巧?如何群发邮件?

邮件群发有哪些注意事项?怎么有效分析邮件群发效果? 邮件群发已经成为一种高效的信息传递手段。然而,很多人发现,尽管发送了大量的邮件,但回应率却并不理想。那么,如何才能在邮件群发中提高成功率呢&#…

只为兴趣,2024年你该学什么编程?

讲动人的故事,写懂人的代码 当你想学编程但不是特别关心找工作的时候,选哪种语言学完全取决于你自己的目标、兴趣和能找到的学习资料。一个很重要的点,别只学一种语言啊!毕竟,"门门都懂,样样皆通",每种编程语言都有自己的优点和适合的用途,多学几种可以让你的…

Day 20 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

最大二叉树 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构建最大二叉…

【鸿蒙千帆起】《开心消消乐》完成鸿蒙原生应用开发,创新多端联动用户体验

《开心消消乐》已经完成鸿蒙原生应用开发,乐元素成为率先完成鸿蒙原生应用开发的20游戏厂商之一。作为一款经典游戏,《开心消消乐》已经拥有8亿玩家,加入鸿蒙原生应用生态,将为其带来更优的游戏性能和更多创新体验。自9月25日华为…

中国500米分辨率月最大EVI数据集

增强型植被指数(EVI)是在归一化植被指数(NDVI)改善出来的,根据大气校正所包含的影像因子大气分子、气溶胶、薄云、水汽和臭氧等因素进行全面的大气校正,EVI大气校正分三步,第一步是去云处理。第…

【SQL Sever】3. 用户管理 / 权限管理

1. 创建登录名/用户/角色 在SQL Server中,创建用户通常涉及几个步骤。 首先,你需要创建一个登录名,然后你可以基于这个登录名在数据库中创建一个用户。 以下是如何做到这一点的步骤和相应的SQL语句: 创建登录名 首先&#xff0c…

Python零基础从小白打怪升级中~~~~~~~文件和文件夹的操作 (1)

第七节:文件和文件夹的操作 一、IO流(Stream) 通过“流”的形式允许计算机程序使用相同的方式来访问不同的输入/输出源。stream是从起源(source)到接收的(sink)的有序数据。我们这里把输入/输…

企业鸿蒙原生应用元服务备案实操基本材料要求

一、要提前准备的主要材料包括 域名,服务器,包名,公钥,MD5值,法人身份证正反两面,邮箱,手机号2个。 域名是备案过的,应为要求域名能打开,还要悬挂备案号。 操作时要提前沟…

目标检测——瓶装白酒疵品检测数据集

一、重要性及意义 瓶装白酒疵品检测在白酒生产过程中具有极其重要的地位,其重要性和意义主要体现在以下几个方面: 首先,瓶装白酒疵品检测是保障消费者权益的关键环节。白酒作为消费者日常饮用的酒类之一,其品质直接关系到消费者…

【电控笔记4】拉普拉斯-传递函数-pid

数据标幺化 拉普拉斯变换 欧拉公式 常见s变换 s变换性质 pid分析 p控制,存在稳态误差 可以求出p的取值范围p>-1,否则发散 pi消除稳态误差 把kp换成Gs 只用pi控制,不加微分的原因: 微分之后,噪声增大高频噪声频率…

【研发管理】产品经理知识体系-数字化战略

导读: 数字化战略对于企业的长期发展具有重要意义。实施数字化战略需要企业从多个方面进行数字化转型和优化,以提高效率和创新能力,并实现长期竞争力和增长。 目录 1、定义 2、数字化战略必要性 3、数字战略框架 4、数字化转型对产品和服务设计的影响…

卷积通用模型的剪枝、蒸馏---剪枝篇(此处以deeplabv3+为例,可根据模型自行定制剪枝层)

之后的两篇文章是对前段时间工作的一个总结。 一、环境配置 1.1、文章以b导的代码为模板,环境配置比较简单(第二篇蒸馏篇结束后会放置剪枝蒸馏配置好的百度网盘链接),其他算法自行配置,在剪枝之前,需要保证算法能够在本地跑通。 B导链接: https://github.com/bubbliiiin…

行云堡垒国密算法应用与信创支持

一、 国密算法和信创的介绍 1.1 什么是国密算法 国密算法是国家密码管理局制定颁布的一系列的密码标准,即已经被国家密码局认定的国产密码算法,又称商用密码(是指能够实现商用密码算法的加密,解密和认证等功能的技术)…

.NET邮箱API发送邮件的流程?如何使用API?

.NET邮箱API发送邮件需要哪些步骤?怎么配置API发信? 电子邮件已经成为我们日常工作和生活中不可或缺的一部分。对于开发人员来说,掌握如何使用API发送邮件是一项非常实用的技能。AokSend将详细介绍使用.NET邮箱API发送邮件的流程&#xff0c…

机器学习和深度学习 -- 李宏毅(笔记与个人理解1-6)

机器学习和深度学习教程 – 李宏毅(笔记与个人理解) day1 课程内容 什么是机器学习 找函数关键技术(深度学习) 函数 – 类神经网络来表示 ;输入输出可以是 向量或者矩阵等如何找到函数: supervised Lear…

电感在 DC/DC 变换器中的作用及选型指南

消费类应用是现代 DC/DC 变换器需求的主要驱动力。在这类应用中,功率电感主要被用于电池供电设备、嵌入式计算,以及高功率、高频率的 DC/DC 变换器。了解电感的电气特性对于设计紧凑型、经济型、高效率、并具备出色散热性能的系统至关重要。 电感是一种…

3D模型可视化引擎HOOPS Visualize如何实现大型工厂可视化管理?

随着工业技术的不断发展,大型工厂的管理和运营面临着越来越多的挑战。为了提高效率、降低成本和优化生产流程,工厂管理者越来越倾向于采用先进的可视化技术来进行工厂管理。在这一领域中,3D模型可视化引擎HOOPS Visualize正发挥着越来越重要的…

Java项目:基于SSM+vue框架实现的人力资源管理系统设计与实现(源码+数据库+毕业论文+任务书)

一、项目简介 本项目是一套基于SSM框架实现的人力资源管理系统 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse或者idea 确保可以运行! 该系统功能完善、界面美观、操作简单、功能…