redis持久化方式—AOF

2024-06-18 11:55
文章标签 redis 方式 持久 aof

本文主要是介绍redis持久化方式—AOF,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

redis为什么需要持久化

redis是内存数据库,redis所有的数据都保存在内存中

如果此时pc关机或重启,那么内存中的用户数据岂不是丢失了?redis这么不安全吗?

作为数据库,保证数据的安全,持久是基本需求,redis采用了AOF和RDB两种持久化方式,将用户数据以特殊形式保存在磁盘中,确保重启时可以恢复之前的内存数据状态

AOF(Append Only File)日志

redis的AOF持久化方式是:redis每执行一次写操作,就将对应的命令记录到一个磁盘文件中,redis一旦宕机,重启时重新执行这些命令就可以恢复之前的数据状态

在这里插入图片描述

这种保存写操作命令到日志的持久化方式,就是 Redis 里的 AOF(Append Only File) 持久化功能

写日志的步骤:

1.写入aof内核缓冲区

2.将内核缓冲区的数据写入磁盘

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

1.避免额外的检查,如果一条命令不符合协议的语法,那么这条语句是不会被执行的,如果先写入日志,就会导致恢复数据时,这条命令失效,造成了不必要的性能开销

2.不会阻塞当前写操作的执行,因为执行命令和写日志两个操作都是由主进程进行的,先保证写操作的执行,再进行写日志

AOF持久化的缺陷

1.由于执行写操作和写日志是两个串行的操作,如果在写入日志之前redis故障,就会导致数据丢失

2.写日志操作虽然不会阻塞上一个写操作的执行,但是会阻塞下一个写操作的执行

在这里插入图片描述

问题根源——写日志的时机

我们刚刚介绍的,先执行写操作,随后写日志其实是redis日志写策略的一种,现在介绍redis提供的写日志的三种策略

1.Always:每次进行写操作后,将命令写入aof内核缓冲区,随即写入磁盘

2.Everysec:每次进行写操作后,将命令写入aof内核缓冲区,每隔一秒将数据写入磁盘

3.NO:每次进行写操作后将命令写入aof内核缓冲区,由操作系统决定写磁盘的时机

不难发现,每次进行写操作后都必须将命令写入内核aof内核缓冲区,这个过程并不耗时,容易造成阻塞的是写磁盘操作

三种策略的优缺点:

在这里插入图片描述

操作系统何时将aof缓冲区的数据写入磁盘?

当应用程序向文件写入数据时,内核通常先将数据复制到内核缓冲区中,然后排入队列,然后由内核决定何时写入硬盘,也就是说,内核缓冲区不止由aof的数据,还有其它的数据,真正的写磁盘时机由操作系统的策略决定

写磁盘时机可以由程序员决定吗?
fsync函数是操作系统提供的同步函数,可以强制让操作系统立即将内核缓冲区的数据写入到磁盘中
上面提到的 Always和Everysec两种写磁盘策略本质上就是调用了fsync函数

AOF重写机制

聪明的你,有没有发现AOF日志会记录一些无效信息?

比如,我执行了set name wjq,随后又执行了set name wjq++,此时数据库中name对应的值实际上是wjq++,而wjq这个值被覆盖了,是无效的,而AOF全部记录了这两条命令,并在恢复数据时重新执行这两条命令,而实际上只需要记录第二条命令,这无疑造成了性能浪费

那么,如何判断某条命令(set name wjq)可以不被记录呢?

很简单,只要查看数据库中现有的数据(wjq++),其中的数据是恢复时所必需的

所以,AOF重写机制就是

读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。

重写工作完成后,就会将新的 AOF 文件覆盖现有的 AOF 文件,这就相当于压缩了 AOF 文件,使得 AOF 文件体积变小了。

AOF后台重写

之所以使用AOF重写机制,不是因为AOF记录了无效的信息,而是因为当数据量过大时,AOF文件占用空间过多,我们需要将AOF文件进行压缩

所以,AOF重写机制的触发时机是:当 AOF 文件大于 64M 时

触发 AOF 重写时,比如当 AOF 文件大于 64M 时,就会对 AOF 文件进行重写,这时是需要读取所有缓存的键值对数据,并为每个键值对生成一条命令,然后将其写入到新的 AOF 文件,重写完后,就把现在的 AOF 文件替换掉

你有没有发现,在正常的AOF日志写操作时,是对每一条命令写入aof缓冲区,这个过程并不耗时

但AOF重写时,AOF文件已经超过了64M,这时进行生成命令、写入新文件的操作相当耗时,万万不能放在主进程中进行,那怎么办呢?

所以,Redis 的重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的

当需要进行AOF重写时,fork出一个子进程,由子进程执行重写操作,这样就不会阻塞主进程了

重写期间数据不一致的问题

考虑这样的情况:在子进程进行AOF重写操作时,主进程添加或修改了新的数据,这时子进程只拥有fork时刻的父进程的副本,而没有新添加的数据,并且在AOF重写完成后会用新AOF文件覆盖旧的AOF文件,也就是说,这种数据不一致会导致AOF重写期间添加和修改的数据丢失

解决:

既然在AOF重写期间的新数据只会出现在父进程,而不会出现在子进程,那我们将新数据追加到子进程不就好了

方案:

父进程拥有aof缓冲区

子进程拥有aof重写缓冲区

1.先执行客户端发送的写操作命令

2.将命令写入父进程aof缓冲区

3.将命令写入子进程aof重写缓冲区

这样就解决了父子进程数据不一致和数据丢失的问题

总结

1.AOF日志的持久化具体过程:每执行一条写命令,将该命令写入aof缓冲区,然后由三种写策略(always、everysec、no)决定何时将aof缓冲区数据写入磁盘文件

2.在数据库恢复时,重放磁盘中AOF文件中保存的命令,就实现了内存数据的恢复

3.由于aof记录每一条写命令,会造成记录无效数据的情况,并且数据量大时,aof文件的体积也会过大

为缓解aof的空间占用,redis设计了aof重写的机制,它会扫描数据库中的键值对,并为之生成命令,写入一个新的aof文件中,全部键值对写入完成后,新的aof文件会覆盖旧aof文件,这个过程避免了无效命令的记录,压缩了aof文件体积

大时,aof文件的体积也会过大

为缓解aof的空间占用,redis设计了aof重写的机制,它会扫描数据库中的键值对,并为之生成命令,写入一个新的aof文件中,全部键值对写入完成后,新的aof文件会覆盖旧aof文件,这个过程避免了无效命令的记录,压缩了aof文件体积

不过由于执行aof重写操作的时机是旧aof文件超过64M,也就是说aof重写操作将会很耗时,redis使用一个fork出的子进程来执行这个任务,但是在子进程进行aof重写时,如果父进程产生了新aof数据,会造成数据不一致,且在子进程完成aof重写并覆盖旧aof文件后,这些多出的不一致数据会丢失,所以在aof重写期间追加的新aof数据会先写入父进程aof缓冲区,再写入子进程aof重写缓冲区,解决了数据不一致和数据丢失的问题

推荐学习 https://xxetb.xetslk.com/s/p5Ibb

这篇关于redis持久化方式—AOF的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071976

相关文章

CSS引入方式和选择符的讲解和运用小结

《CSS引入方式和选择符的讲解和运用小结》CSS即层叠样式表,是一种用于描述网页文档(如HTML或XML)外观和格式的样式表语言,它主要用于将网页内容的呈现(外观)和结构(内容)分离,从而实现... 目录一、前言二、css 是什么三、CSS 引入方式1、行内样式2、内部样式表3、链入外部样式表四、CSS 选

PyTorch高级特性与性能优化方式

《PyTorch高级特性与性能优化方式》:本文主要介绍PyTorch高级特性与性能优化方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、自动化机制1.自动微分机制2.动态计算图二、性能优化1.内存管理2.GPU加速3.多GPU训练三、分布式训练1.分布式数据

Python文件操作与IO流的使用方式

《Python文件操作与IO流的使用方式》:本文主要介绍Python文件操作与IO流的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、python文件操作基础1. 打开文件2. 关闭文件二、文件读写操作1.www.chinasem.cn 读取文件2. 写

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

C++类和对象之初始化列表的使用方式

《C++类和对象之初始化列表的使用方式》:本文主要介绍C++类和对象之初始化列表的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C++初始化列表详解:性能优化与正确实践什么是初始化列表?初始化列表的三大核心作用1. 性能优化:避免不必要的赋值操作2. 强

防止SpringBoot程序崩溃的几种方式汇总

《防止SpringBoot程序崩溃的几种方式汇总》本文总结了8种防止SpringBoot程序崩溃的方法,包括全局异常处理、try-catch、断路器、资源限制、监控、优雅停机、健康检查和数据库连接池配... 目录1. 全局异常处理2. 使用 try-catch 捕获异常3. 使用断路器4. 设置最大内存和线

Redis持久化机制之RDB与AOF的使用

《Redis持久化机制之RDB与AOF的使用》:本文主要介绍Redis持久化机制之RDB与AOF的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Redis持久化机制-RDB与AOF一、RDB持久化机制1、RDB简介2、RDB的工作原理3、RDB的优缺点4

基于Redis实现附近商铺查询功能

《基于Redis实现附近商铺查询功能》:本文主要介绍基于Redis实现-附近商铺查询功能,这个功能将使用到Redis中的GEO这种数据结构来实现,需要的朋友可以参考下... 目录基于Redis实现-附近查询1.GEO相关命令2.使用GEO来实现以下功能3.使用Java实现简China编程单的附近商铺查询4.Red