【Redis—持久化】

news2024/11/19 1:21:23

1.持久化机制

  • 持久化就是把内存的数据写到磁盘中,防止服务宕机导致内存数据丢失。

2.AOF

AOF概述

  • AOF持久化:以独立日志就把该命令。以追加的方式写入到一个文件里,然后重启 Redis 的时候,先去读取这个文件里的命令达到恢复目数据的目的。
  • 在 Redis 中 AOF 持久化功能默认是不开启的,需要我们修改 redis.conf 配置文件中的以下参数:appendonly yes

注意只会记录写操作命令,读操作命令是不会被记录的,因为没意义。

在这里插入图片描述

  • Redis 是先执行写操作命令后,才将该命令记录到 AOF 日志里的,这么做有好处也有风险。
'优点'
        1. 避免额外的检查开销。(如果先写AOF日志,如果当前命令有语法问题,不进行语法检查,记录错误的AOF文件,当重启后执行的是错误的AOF文件)
        2. 不会阻塞当前写操作命令的执行
'缺点'
        1. 执行写操作命令和记录日志是两个过程,那当 Redis 在还没来得及将命令写入到硬盘时,服务器发生宕机了,这个数据就会有丢失的风险。
        2. 由于写操作命令执行成功后才记录到 AOF 日志,所以不会阻塞当前写操作命令的执行,但是可能会给「下一个」命令带来阻塞风险。
  • 因为将命令写入到日志的这个操作也是在主进程完成的(执行命令也是在主进程),也就是说这两个操作是同步的。
  • 如果在将日志内容写入到硬盘时,服务器的硬盘的 I/O 压力太大,就会导致写硬盘的速度很慢,进而阻塞住了,也就会导致后续的命令无法执行。

在这里插入图片描述

AOF写到磁盘的过程

在这里插入图片描述
流程:

  1. Redis 执行完写操作命令后,会将命令追加到 server.aof_buf 缓冲区;
  2. 然后通过 write() 系统调用,将 aof_buf 缓冲区的数据写入到 AOF 文件,此时数据并没有写入到硬盘,而是拷贝到了内核缓冲区 page cache,等待内核将数据写入硬盘;
  3. 内核调用fsync函数将内核缓冲区的数据根据对应的策略向硬盘同步。
  4. 随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩体积目的(AOF重写是把Redis进程内的数据转换为写命令同步到新的AOF文件的过程)
  5. Redis服务重启后,加载AOF文件进行恢复。

步骤3:Redis 提供了 3 种写回硬盘的策略

appendfsync Always        每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘;
appendfsync Everysec      每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘;
appendfsync No            不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘。

优点

  • 为了让AOF更好的保护数据不丢失,可以配置AOF每秒执行一次fsync操作,如果redis进程挂掉,最多丢失1秒数据

缺点

  1. 对于同一份文件AOF文件比RDB数据快照要大。
  2. 数据恢复慢

AOF重写过程

  • AOF 重写机制是在重写时,读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。
  • 先写到新的 AOF 文件再覆盖过去。因为如果 AOF 重写过程中失败了,现有的 AOF 文件就会造成污染,可能无法用于恢复使用。

AOF后台重写

  • 写入 AOF 日志的操作虽然是在主进程完成的,因为它写入的内容不多,一般不影响命令的操作。但是触发AOF重写需要重写一份AOF文件,并且将重写的AOF文件,覆盖掉旧AOF文件。此时非常耗时。所以Redis 的重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的

优点

  • 子进程进行 AOF 重写期间,主进程可以继续处理命令请求,从而避免阻塞主进程;
  • 子进程带有主进程的数据副本,这里使用子进程而不是线程,因为如果是使用线程,多线程之间会共享内存,那么在修改共享内存数据的时候,需要通过加锁来保证数据的安全,而这样就会降低性能。而使用子进程,创建子进程时,父子进程是共享内存数据的,不过这个共享的内存只能以只读的方式,而当父子进程任意一方修改了该共享内存,就会发生「写时复制」,于是父子进程就有了独立的数据副本,就不用加锁来保证数据安全。

子进程拥有主进程一样的数据副本

  1. 主进程在通过 fork 系统调用生成 bgrewriteaof 子进程时,操作系统会把主进程的「页表」复制一份给子进程,这个页表记录着虚拟地址和物理地址映射关系,而不会复制物理内存,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。
  2. 当父进程或者子进程在向这个内存发起写操作时,CPU 就会触发写保护中断,这个写保护中断是由于违反权限导致的,然后操作系统会在「写保护中断处理函数」里进行物理内存的复制,并重新设置其内存映射关系,将父子进程的内存读写权限设置为可读写,最后才会对内存进行写操作(写时复制

进行复制的时候有两个阶段会导致阻塞父进程:

  • 创建子进程的途中,由于要复制父进程的页表等数据结构,阻塞的时间跟页表的大小有关,页表越大,阻塞的时间也越长;
  • 创建完子进程后,如果子进程或者父进程修改了共享数据,就会发生写时复制,这期间会拷贝物理内存,如果内存越大,自然阻塞的时间也越长;

AOF缓冲区

  1. 触发重写机制后,主进程就会创建重写 AOF 的子进程,此时父子进程共享物理内存,重写子进程只会对这个内存进行只读,重写 AOF 子进程会读取数据库里的所有数据,并逐一把内存数据的键值对转换成一条命令,再将命令记录到重写日志(新的 AOF 文件)。
  2. 子进程重写过程中,主进程依然可以正常处理命令。
  3. 主进程修改了已经存在 key-value,就会发生写时复制,注意这里只会复制主进程修改的物理内存数据,没修改物理内存还是与子进程共享的。

此时会出现数据不一致现象,于是使用AOF重写缓冲区。

  • 在重写 AOF 期间,当 Redis 执行完一个写命令之后,它会同时将这个写命令写入到 「AOF 缓冲区」和 「AOF 重写缓冲区」。

重写流程

在这里插入图片描述

  • 在 bgrewriteaof 子进程执行 AOF 重写期间,主进程需要执行以下三个工作:

    • 执行客户端发来的命令;
    • 将执行后的写命令追加到 「AOF 缓冲区」;
    • 将执行后的写命令追加到 「AOF 重写缓冲区」;
  • 当子进程完成 AOF 重写工作(扫描数据库中所有数据,逐一把内存数据的键值对转换成一条命令,再将命令记录到重写日志)后,会向主进程发送一条信号,信号是进程间通讯的一种方式,且是异步的。

  • 主进程收到该信号后,会调用一个信号处理函数:

    • 将 AOF 重写缓冲区中的所有内容追加到新的 AOF 的文件中,使得新旧两个 AOF 文件所保存的数据库状态一致;
    • 新的 AOF 的文件进行改名,覆盖现有的 AOF 文件。

3.RDB

概述

  • 快照持久化是Redis默认采用的持久化方式,在Redis.conf配置文件中默认有此下配置:
save 900 1 #在900(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令
创建快照。
save 300 10 #在300(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000 #在60(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

  • RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据,而 AOF 文件记录的是命令操作的日志,而不是实际的数据。因此在 Redis 恢复数据时, RDB 恢复数据的效率会比 AOF 高些,因为直接将 RDB 文件读入内存就可以,不需要像 AOF 那样还需要额外执行操作命令的步骤才能恢复数据。
  • Redis 的快照是全量快照,也就是说每次执行快照,都是把内存中的「所有数据」都记录到磁盘中。

Redis 提供了两个命令来生成 RDB 文件,分别是 savebgsave,他们的区别就在于是否在「主线程」里执行:

  • 执行了save命令,就会在主线程生成 RDB 文件,由于和执行操作命令在同一个线程,所以如果写入 RDB 文件的时间太长,会阻塞主线程;
  • 执行了 bgsave 命令,会创建一个子进程来生成 RDB 文件,这样可以避免主线程的阻塞;

RDB缺点

  • 执行快照是一个比较重的操作,在服务器发生故障时,丢失的数据会比 AOF 持久化的方式更多,因为 RDB 快照是全量快照的方式,因此执行的频率不能太频繁,否则会影响 Redis 性能,如果频率太低,服务器故障时,丢失的数据会更多。而 AOF 日志可以以秒级的方式记录操作命令,所以丢失的数据就相对更少。

RDB优点

  • Redis加载RDB恢复数据远远快于AOF的方式

bgsave执行流程

  • RDB是Redis默认的持久化方案。RDB持久化时会将内存中的数据写入到磁盘中,在指定目录下生成一个dump.rdb文件。Redis重启会加载dump.rdb文件恢复数据。
  • bgsave是主流的触发RDB持久化的方式,执行过程如下:

在这里插入图片描述

  1. 执行BGSAVE命令
  2. Reids父进程判断当前是否存在正在执行的子进程,如果存在,BGSAVE命令直接返回。
  3. 父进程执行fork操作创建子进程fork操作过程中父进程会阻塞。
  4. 父进程fork完成后,父进程继续接收并处理客户端的请求,而子进程开始将内存中的数据写进硬盘的临时文件
  5. 当子进程写完所有数据后会用临时文件替换RDB文件

执行快照时,数据能被修改吗?

  • 执行 bgsave 过程中,由于是交给子进程来构建 RDB 文件,主线程还是可以继续工作的Redis 依然可以继续处理操作命令的,也就是数据是能被修改的。(关键的技术就在于写时复制技术(Copy-On-Write, COW))

流程

  1. 执行 bgsave 命令的时候,会通过 fork() 创建子进程,此时子进程和父进程是共享同一片内存数据的,因为创建子进程的时候,会复制父进程的页表,但是页表指向的物理内存还是一个。
  2. 如果主线程(父进程)要修改共享数据里的某一块数据(比如键值对 A)时,就会发生写时复制,于是这块数据的物理内存就会被复制一份(键值对 A’),然后主线程在这个数据副本(键值对 A’)进行修改操作。与此同时,bgsave 子进程可以继续把原来的数据(键值对 A)写入到 RDB 文件。
  3. Redis 使用 bgsave 对当前内存中的所有数据做快照,这个操作是由 bgsave 子进程在后台完成的,执行时不会阻塞主线程,这就使得主线程同时可以修改数据。

注意:

  • bgsave 快照过程中,如果主线程修改了共享数据,发生了写时复制后,RDB 快照保存的是原本的内存数据,而主线程刚修改的数据,是没办法在这一时间写入 RDB 文件的,只能交由下一次的 bgsave 快照。
  • 所以 Redis 在使用 bgsave 快照过程中,如果主线程修改了内存数据,不管是否是共享的内存数据,RDB 快照都无法写入主线程刚修改的数据,因为此时主线程(父进程)的内存数据和子进程的内存数据已经分离了,子进程写入到 RDB 文件的内存数据只能是原本的内存数据。
  • 如果系统恰好在 RDB 快照文件创建完毕后崩溃了,那么 Redis 将会丢失主线程在快照期间修改的数据。

4.混合持久化

  • 如果频率太低,两次快照间一旦服务器发生宕机,就可能会比较多的数据丢失;
  • 如果频率太高,频繁写入磁盘和创建子进程会带来额外的性能开销。

开启混合持久化功能,可以在 Redis 配置文件将下面这个配置项设置成 yes:

aof-use-rdb-preamble yes
  1. 当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里
  2. 重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
在这里插入图片描述

优点

  • 重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快。
  • 加载完 RDB 的内容后,才会加载后半部分的 AOF 内容,这里的内容是 Redis 后台子进程重写 AOF 期间,主线程处理的操作命令,可以使得数据更少的丢失。

文章:https://www.xiaolincoding.com/redis/storage/aof.html

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

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

相关文章

K8S-存储-Volume

问题 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃 时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。…

IDEA 控制台日志中文乱码解决方案

老白新学JAVA,初用IDEA,控制台打印中文总是乱码,网上找了好多解决方法,都不好用,下面记录解决过程。 1.修改idea64.exe.vmoptions ,打开最后一行增加如下代码 idea快捷方式右键->属性->打开文件所有位置&#x…

Redis 性能优化 —— 内存碎片

文章目录一、内存碎片场景描述二、内存碎片概念解析三、内存碎片产生原因四、内存碎片如何判断五、内存碎片解决方案六、内存碎片扩展技能一、内存碎片场景描述 作为内存数据库,内存空间的大小对于 Redis 来说是至关重要的。内存越多意味着存储的数据也会越多&#…

多线程下对象的析构问题

多线程遇上对象析构是个很麻烦的问题,这里我用一个多线程的单例模式去演示一下对象析构的问题 懒汉模式,加锁,线程安全 懒汉模式:需要的时候new一个对象,不需要的时候delete (线程安全的懒汉)单…

服务注册配置中心Nacos

文章目录一. 前言二. 下载安装1. 下载安装包2. Windows环境安装3. Linux环境安装1. 单击模式启动2. 集群模式启动3. 远程web控制4. 注册为系统服务三. 基本使用1. 添加依赖2. 服务注册3. 配置实例集群属性4. 实例权重负载均衡5. 环境隔离6. 临时实例与非临时实例四. Nacos配置管…

Gradle学习笔记之文件操作

文章目录本地文件文件集合文件树文件拷贝归档文件Gradle中的文件操作方式有五种:本地文件、文件集合、文件树、文件拷贝和归档文件。 本地文件 比较简单,API跟java中的完全一致: task("test_file") {doFirst {def f1 file(&quo…

史上最强,这份在各大平台获百万推荐的Java核心手册实至名归

又逢“金九银十”,年轻的毕业生们满怀希望与忐忑,去寻找、竞争一个工作机会。已经在职的开发同学,也想通过社会招聘或者内推的时机争取到更好的待遇、更大的平台。 然而,面试人群众多,技术市场却相对冷淡,…

再学C语言13:字符串(4)——scanf函数

一、scanf函数的使用 scanf函数功能:把输入的字符串转换成各种形式(整数、浮点数、字符、字符串) scanf函数是printf函数的逆操作 scanf函数与printf函数一样使用控制字符串和参数列表 控制字符串指出输入将被转换成的格式 主要区别在参…

Qt实现表格控件

一、概述 最近在研究QTableView支持多级表头的事情,百度了下网上资料还是挺多的。实现的方式总的来说有2种,效果都还不错,最主要是搞懂其中的原理,做到以不变应万变。 实现多级表头的方式有以下两种方案 行表头和列表头都是用一…

网络空间安全——利用 CVE-2017-0213 提权

利用 CVE-2017-0213 提权 VE-2017-0213 是一个比较冷门的COM 类型混淆 (Type Confusion)漏洞。巧妙的利用该漏洞,可以实现本地的提权。该漏洞由著名的Google Project zero 发现。 下面就简单演示一下利用CVE-2017-0213漏洞简单提权, 首先下载CVE-2017…

【环境搭建】RocketMQ集群搭建

前置条件及效果图 条件: 两台服务器,个人是两台腾讯云服务器(其中嫖的朋友一个); 版本: rocketmq-version:4.4.0rocketmq-console(mq控制台)Java:1.8maven:3.6.3 集群模式选择: 单master 这种方式风险…

【Django】第三课 基于Django超市订单管理系统开发

概念 本文在上一文之上,针对管理员,经理,普通员工身份的用户操作供应商管理模块功能。 功能实现 供应商管理模块属于业务功能,这里管理员不具备操作权限,而经理具备与供应商之间谈合作的实际需要,因此经…

Linux | 进程理解,fork | 进程地址空间

文章目录冯诺依曼体系结构的理解为什么要有内存的存在?操作系统的管理进程的理解系统调用接口进程的查看fork进程状态Linux进程具体的状态孤儿进程总结进程优先级怎样修改优先级?进程其他概念进程抢占进程地址空间利用代码验证地址区域验证堆区和栈区的增…

python3GUI--音乐播放器(精简版)By:PyQt5(附下载地址)

文章目录一.前言二.预览1.主界面2.歌单页3.歌词页4.播放列表5.mini6.设置三.心得1.解耦2.体验优化3.歌词显示四.总结一.前言 传送门: 1.python3GUI–打造一款音乐播放器By:PyQt5(附下载地址&am…

LD_PRELOAD劫持

在前面UUCTF的uploadinject题,遇到了 LD_PRELOAD劫持,之前没遇见过,刚好借此机会学一学。不能小瞧这个变量,它甚至可以弹shell,绕过disable_functions,非常危险。下面来介绍一下这个变量,以及怎…

XDocReport使用入门

XDocReport 简介 XDocReport是GitHub上根据麻省理工学院许可证开源的Wrod导出框架。XDocReport可以根据ODT、Doc、Docx文档模板通过模板引擎语法(Freemarker、Velocity)转换为另外一种格式文档(Doc、Docx、XHTML、PDF)。 XDocR…

防沉迷管理系统

开发工具(eclipse/idea/vscode等): 数据库(sqlite/mysql/sqlserver等): 功能模块(请用文字描述,至少200字): 1、用户模块 1.1注册:用户通过注册生产账号,并在数据库存储数据 1.2登录:用户登录后…

k8s学习-CKA真题-k8s升级(kubeadm、kubelet、kubectl等)

目录题目解析命令准备工作升级组件升级kubectl、kubelet收尾结果killer 模拟环境题目解析解题参考题目 解析 结合博主当前环境,调整后题目为: 现有的 Kubernetes 集权正在运行的版本是 1.23.6,仅将主节点上的所有 kubernetes 控制面板和组件…

【语音处理】基于加权压力匹配方法(WPMM)的声音系统研究(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

【小程序】案例 - 本地生活(列表页面)

1. 演示页面效果以及主要功能 页面导航并传参 上拉触底时加载下一页数据 下拉刷新列表数据 2. 列表页面的 API 接口 以分页的形式,加载指定分类下商铺列表的数据: 接口地址 https://www.escook.cn/categories/:cate_id/shops URL 地址中的 :cate…