Redis中AOF文件重写与同步

news/2024/4/27 13:30:02/文章来源:https://blog.csdn.net/Cover_sky/article/details/136986006

AOF文件的写入与同步

Redis服务器进程就是一个时间循环(loop),这个循环中的文件时间负责接收客户端的命令请求,以及向客户端发送命令回复,而时间事件则负责执行像serverCron函数这样需要定时运行的函数。因为服务器在处理文件事件时可能会执行些命令,使得一些内容被追加到aof_buf缓冲区里面,所以
在服务器每次结束一个事件循环之前,它都会调用flushAppendOnlyFile函数,考虑是否将aof_buf缓冲区中的内容写入和保存到AOF文件里面,这个过程可以用以下伪代码表示

def eventLoop():while True :# 处理文件事件,接收命令请求以及发送命令回复# 处理命令请求时可能会有新内容被追加到aof_buf缓冲区中processFileEvents()# 处理时间事件processTimeEvents()# 考虑是否要将aof_buf中的内容写入和保存到AOF文件里面flushAppendOnlyFile()

flushAppendOnlyFile函数的行为由服务器配置的appendfsync选项的值来决定,各个不同的值产生的行为也不同,如果用户没有主动为appendfsync选项设置值,那么appendfsync选项的默认值为everysec

文件的写入和同步

为了提高文件的写入效率,在现代操作系统中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通产会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满,或者超过了指定
的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。这种做法虽然提高了效率,但也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。为此,系统提供
了fsync和fdatasync两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性

AOF持久化的效率和安全性

服务器配置appendfsync选项的值直接决定AOF持久化功能的效率和安全性。

  • 1.当appendfsync的值为always时,服务器在每个事件循环都要讲aof_buf缓冲区中的所有内容写入到AOF文件并且同步AOF文件,所以always的效率时appendfsync选项三个当中最慢的一个,但从安全性来说,always也是最安全的,因为即使出现故障停机,AOF持久化也只会丢失一个事件循环中所产生的命令数据
  • 2.当appendfsync的值为everysec时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件并且每隔一秒就要在子线程中对AOF文件进行一次同步。从效率上来讲,everysec模式足够快,并且就算出现故障停机,数据库也只丢失一秒钟的命令数据
  • 3.当appendfsync的值为no时,服务器在每隔事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,至于何时对AOF文件进行同步,则由操作系统控制。因为处于no模式下的flushAppendOnlyFile调用无须执行同步操作,所以该模式下的AOF文件写入速度总是最快的,不过因为这种模式会在系统缓存中积累一段时间的写入数据,所以该模式的单次同步时长通常是三种模式中时间最长的。从平摊操作的角度来看,no模式和everysec模式的效率类似,当出现故障停机时,使用no模式的服务器将丢失上次同步AOF文件之后的所有写命令数据

例子

  • 例如,对于以下AOF文件来说
*2
$6
SELECT
$1
0
*5
$4
SADD
$6
fruits
$6
banana
$6
cherry
$5
apple
*3
$3
SET
$3
msg
$5
hello
*5
$5
RPUSH
$7
numbers
$3
128
$3
256
$3
512

AOF文件的载入与数据还原

因为AOF文件里面包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态。Redis读取AOF文件并还原数据库状态的详细步骤如下:

  • 1.创建一个不带网络连接的伪客户端(fake client):因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样。
  • 2.从AOF文件中分析并读取出一条写命令
  • 3.使用伪客户端执行被读出的写命令
  • 4.执行步骤2和步骤3,直到AOF文件中的所有写命令被处理完毕为止
    当完成以上步骤之后,AOF文件所保存的数据库状态就会被万丈地还原出来,整个过程如图
    在这里插入图片描述
    服务器首先读入并执行SELECT 0命令,之后是SET msg hello命令,在之后是SADD fruits apple banana cherry命令,最后是RPUSH numbers 128 256 512 命令,当这些命令都执行完毕之后,服务器的数据库就被还原到之前的状态了,

整个重写过程可以用以下伪代码表示:

def aof_rewrite(new_aof_file_name):# 创建新的AOF文件f = create_file(new_aof_file_name)# 遍历数据库for db in redisServr.db:# 忽略空数据if db.is_empth(): continue# 写入SELECT命令,指定数据库索引f.write_command("SELECT" + db.id)# 遍历数据库中的所有键for key in db:# 忽略已过期的键if key.is_expired(): continue# 根据键的类型对键进行重写if key.type == String:rewrite_string(key)elif key.type == List:rewrite_list(key)elif key.type == Hash:rewrite_hash(key)elif key.type == Set:rewrite.set(key)elif key.type == SortedSet:rewrite_sorted_set(key)# 如果键带有过期时间,那么过期时间也要被重写if key.have_expire_time():rewrite_expir_time(key)
# 写入完毕,关闭文件
f.close()def rewrite_string(key):# 使用GET命令获取字符串键的值value = GET(key)# 使用SET命令重写字符串键f.write_command(SET,key,value)def rewrite_list(key):# 使用LRANGE命令获取列表键包含的所有元素item1, item2, item3, ....itemN = LRANGE(key, 0, -1)# 使用RPUSH命令重写列表键f.write_command(RPUSH, key, item1, item2, item3,...,itemN)def rewrite_hash(key):# 使用HGETALL命令后去哈希键包含的所有键值对field1, value1, field2, value2, fieldN, valueN = HGETALL(key)# 使用HMSET命令重写哈希键f.write_command(HMSET, key, field1, value1, field2,value2,...,fieldN, valueN)def rewrite_set(key):# 使用SMEMBERS命令获取集合键包含的所有元素elem1, elem2, elem3,....,elemN = SMEMBERS(key)# 使用SADD命令重写集合键f.write_command(SADD, key, elem1, elem2,...elemN)def rewrite_sorted_set(key):# 使用ZRANGE命令获取有序集合键包含的新元素member1,score1, member2,score2,..., memberN, scoreN = ZRANGE(key, 0, -1, "WOTJSCPRES")# 使用ZADD命令重写有序集合键f.write_command(ZADD, key, score1, memeber1, score2, member2, ...., scoreN, memberN)def rewrite_expire_time(key):# 获取毫秒精度的键过期时间戳timestamp = get_expire_time_in_unixstamp(key)# 使用PEXIREAT命令重写键的过期时间f.write_command(PEXIREAT, key, timestamp
)

因为aof_rewrite函数生成的AOF文件只包含还原当前数据库状态所必须的命令,所以新AOF文件不会浪费任何硬盘空间

AOF文件重写的实现

虽然Redis将生成新AOF文件替换旧AOF文件的功能命名为"AOF文件重写",但实际上,AOF文件重写并不需要对现有的AOF文件进行任何读取、分析或者写入操作,这个功能是通过读取服务器当前的数据库状态来实现的。

例子

  • 举个例子,如果对服务器对list键执行了以下命令:
127.0.0.1:6379> RPUSH list "A" "B" // ["A", "B"]
(integer) 2
127.0.0.1:6379> RPUSH list "C" // ["A", "B", "C"]
(integer) 3
127.0.0.1:6379> RPUSH list "D" "E" // ["A", "B", "C", "D", "E"]
(integer) 5
127.0.0.1:6379> LPOP list // ["B", "C", "D", "E"]
"A"
127.0.0.1:6379> LPOP list // ["C", "D", "E"]
"B"
127.0.0.1:6379> RPUSH list "F" "G" // ["C", "D", "E", "F", "G"]
(integer) 5

那么服务器为了保存当前list键的状态,必须在AOF文件中写入六条命令。
如果服务器想要用尽量少的命令来记录list键的状态,那么最简单高效的办法不是去读取和分析现有的AOF文件的内容,而是直接从数据库中读取键list的值,然后用一条RPUSH list “C” “D” “E” “F” "G"命令来代替保存在AOF文件中的六条命令这样旧可以将保存list键所需的命令从六条减少为一条了

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

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

相关文章

【Java程序设计】【C00416】基于(JavaWeb)Springboot的客户管理系统(含论文)

基于(JavaWeb)Springboot的客户管理系统(含论文) 项目简介项目获取开发环境项目技术运行截图 博主介绍:java高级开发,从事互联网行业六年,已经做了六年的毕业设计程序开发,开发过上千…

C# 文件操作

文章目录 C# 文件操作创建文件运行结果 写入文件程序文件运行结果 WriteAllLines-写入多行运行结果 追加字符串运行结果追加多行字符串 读取文件ReadAllText运行结果 ReadAllLines-用数组接收读取的内容运行结果 采用流(Stream)的方式来读取内容运行结果…

stm32平衡车

目录 一.所需材料 二.PID算法(简单说明) 直立环 速度环 串级PID 三.使用到的外设 1.定时器输出比较-PWM 2.定时器编码器模式 3.编码器读取速度 4.电机驱动函数 5.外部中断 四、小车 调试 一.所需材料 1.陀螺仪MPU6050--读取三轴的加速度…

C++:梦的开始——创建第一个hello world(1)

我这里使用的编写代码的工具是Start Experimental Instance of Visual Studio 2022 你可以去微软的官网上寻找,并且安装 部署项目 项目就是一个文件夹,他将我们的数据都放到了里面,这就是一个项目 在Visual Studio 2022中 选择c 的空项目&a…

【Linux 08】进程概念

文章目录 🌈 01. 基本概念🌈 02. 描述进程 PCB🌈 03. 使用 ./ 的方式创建进程🌈 04. ps 查看进程🌈 05. getpid / getppid 获取进程标识符🌈 06. kill 终止指定进程🌈 07. fork 创建子进程&…

python学习14:python中的表达式

python中的表达式 1.表达式是什么呢? 表达式就是一个具有明确结果的代码语句,如11、type(‘字符串’)、3*5等 在定义变量的时候,如age108,等号右侧的就是表达式,也就是有具体的结果,将结果赋值给了等号左侧的变量 2.…

Linux 系统基础操作命令

当前市面上常见的系统:Windows、Linux、Mac OS、Android、IOS…… Linux 不太适合日常使用,但是非常适合用于开发。因此作为一个程序猿来说,Linux 都是务必要掌握的。 Linux 介绍 Linux 发行版 目前市面上比较知名的发行版有:R…

DNS隧道攻击

什么是DNS隧道? DNS隧道是一种网络通信技术,它利用DNS(Domain Name System,域名系统)协议来建立隐蔽的通信通道。在正常情况下,DNS协议主要用于将域名解析为IP地址,但攻击者可以通过构造特殊的…

总结 | vue3项目初始化(附相应链接)

如何运行 vue 项目:vscode运行vue项目_vscode启动vue项目命令-CSDN博客 vue3项目搭建 目录管理 git管理:vue3项目搭建并git管理_git 新建vue3项目-CSDN博客 目录调整:vue3项目 - 目录调整-CSDN博客 vscode中快速生成vue3模板&#xff1a…

实现能效升级 | 基于ACM32 MCU的冰箱压缩机变频方案

概述 冰箱制冷系统中最重要的部件是压缩机。它从吸气管吸入低温低压的制冷剂气体,通过电机运转带动活塞对其进行压缩后,向排气管排出高温高压的制冷剂气体,为整个制冷循环提供源动力。这样就实现了压缩→冷凝→膨胀→蒸发 ( 吸热 ) 的制冷循环…

并查集|1971. 寻找图中是否存在路径、684.冗余连接、685.冗余连接II

目录 并查集基础 1971. 寻找图中是否存在路径 684.冗余连接 685.冗余连接II 并查集基础 并查集主要有三个功能。 寻找根节点,函数:find(int u),也就是判断这个节点的祖先节点是哪个将两个节点接入到同一个集合,函数&#xf…

项目中自动引入神器 - unplugin-auto-import/unplugin-vue-components

前端 项目中 自动引入 神器 前言 在开发中,我们总喜欢站在巨人的肩膀上开发,比如用一些 框架:vue,react, 组件库:element,ant。 工具函数:axios,lodash 现在是模块化时代,我们…

新手入门C语言之联合体和枚举

在上一篇文章中,我们了解到在C语言中,自定义类型有三种,这里我们介绍后两种,联合体和枚举。 一.联合体 1.联合体的声明 像结构体一样,联合体也是由一个或多个成员构成,这些成员的类型可以是不一样的&…

Go——结构体

Go语言中没有类的概念,也不支持类的继承等面向对象的概念。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。 一. 类型别名和自定义类型 1.1 自定义类型 在Go语言中有一些基本的数据类型,如string,整型,…

手机网页关键词视频爬虫采集软件可导出视频分享链接|视频无水印批量下载工具

全新音视频批量下载工具,为您解放视频管理烦恼! 现如今,音上涌现出大量精彩的视频内容,但是要想高效地获取、管理和分享这些视频却是一件颇具挑战的事情。针对这一难题,我们自主研发了全新的音视频批量下载工具&#x…

数学建模体育建模和经济建模国防科大版

目录 6.体育中的数学建模 7.经济学问题中的数学建模 7.1.实物交换模型 7.2.边际效应 7.3.最佳消费选择模型 6.体育中的数学建模 体育科学的研究中,也有大量的数学建模问题,例如:棒球的最佳击球点问题、滑板滑雪赛道的设计、越野自行车比…

各种需要使用的方法-->vue/微信小程序/layui

各种需要使用的方法-->vue/微信小程序/layui 1、vue里样式不起作用的方法,可以通过deep穿透的方式2、 js获取本周、上周、本月、上月日期3、ArrayBuffer Blob 格式转换ArrayBuffer与Blob的区别ArrayBuffer转BlobBlob转ArrayBuffer需要借助fileReader对象 4、使用…

STM32使用滴答定时器实现delayms

在STM32上使用SysTick实现jiffies(时间戳)并且实现delay_ms 代码实现: volatile uint32_t jiffies 0; // 用于记录系统运行的jiffies数 void SysTick_Handler(void) {/* 每次SysTick中断,jiffies增加 */jiffies; }uint32_t tick…

如何利用生成式人工智能挑选合适的候选人?

在当今激烈的商业竞争中,招聘合适的人才是构建企业成功的基石。筛选和面试候选人是一个复杂且精细的过程,它不仅关系到职位的有效填补,更影响到企业的长期发展和团队建设。 选择合适候选人的重要性 选择合适的候选人就像寻找一片沙滩上的珍…

曲线生成 | 图解Reeds-Shepp曲线生成原理(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 什么是Reeds-Shepp曲线?2 Reeds-Shepp曲线的运动模式3 Reeds-Shepp曲线算法原理3.1 坐标变换3.2 时间翻转(time-flip)3.3 反射变换(reflect)3.4 后向变换(backwards) 4 仿真实现4.1 ROS C实现4.2 Python实现4.3 Matlab实现 0 专栏介绍 &#x1f5…