深入浅出Redis持久化

文章目录

  • 前言
  • RDB
    • 快照原理
    • 保存时机
  • AOF
    • 同步策略
    • AOF重写
  • 混合持久化
  • 总结

前言

redis作为内存数据库,数据都在内存里,如果突然宕机,则数据都会丢失(这里假设不使用非易失性内存),redis提供了持久化机制来防止这种情况发生

如果将redis仅作为缓存使用,且不需要宕机后快速生成缓存数据,可以不使用持久化机制,还能提升性能

redis提供了以下两种持久化方式:

  • RDB(redis database):定时将某一时刻内存中的数据保存到磁盘上
  • AOF(append only file):通过持续增量记录redis的写命令来持久化数据

下面介绍其原理和实现

RDB

快照原理

redis通过定时将内存中某一时刻的快照持久化到磁盘上,来实现数据保存

redis怎么“捕获”某一时刻的快照?

一个简单的想法是,在持久化的过程中,不处理任何请求,也就是执行save命令

但这样会阻塞线上业务,更好的做法是:边持久化边响应客户请求,也就是bgsave命令

以快照的方式持久化,需要保证获取的是“一致性”的快照

什么意思呢?在持久化的过程中,如果先持久化了内存的前半部分,再持久化后半部分,可能在持久化后半部分时,又有请求同时写了前,后半部分的数据。而此时前半部分已经持久化完毕,不会修改了。这样前后两部分的数据就是“不一致”

举个例子:
在这里插入图片描述

  1. 内存中一开始A=1,B=2
  2. 将A=1序列化到磁盘
  3. 某请求在内存中将A,b修改为2,此时磁盘上A=1
  4. 继续序列化,将B=2写入磁盘
  5. 出现问题,此时磁盘中是不合法的数据,因为内存中从来没有某一时刻是A=1,B=2,也就是说A的老版本B的新版本混在一起了

那怎么获取一致性的快照呢?

  • Mysql Innodb的可重复读隔离级别采用MVCC的方式,使得每次的读操作获取的都是一致性的数据,同时不阻塞其他读写请求
  • redis采用多进程写时复制(copy on write)技术来实现

当redis服务端收到bgsave命令时,调用fork函数产生一个子进程,由该子进程创建RDB文件,主进程继续响应客户请求

刚创建子进程时,其和父进程共享数据段,这是操作系统节约内存的机制

只有在某进程需要对数据进行修改时,才会将其复制一份,单独给自己使用,才这个复制出来的页面进行修改。也就是说,子进程在生成快照的过程中需要遍历的页面,是不会被修改的,永远是刚fork出来的样子。

刚fork出来的页面肯定是那一时刻的一个一致性快照,因此将其序列化到磁盘没有任何问题

保存时机

redis在什么时机会触发一次fork子进程生成快照文件的操作呢?

若在配置文件中进行如下save配置:

save 900 1

save 300 10

save 60 3600

以上配置表示redis会在以下情况满足时,自动执行bgsave命令:

  • 900秒内至少1个key发送变化(新增,修改,删除)
  • 300秒内至少10个key发送变化
  • 60秒内至少3600个key发送变化

为什么需要配置多个规则?

试想如果只有中间的规则(300秒内至少10个key发送变化)

那如果redis中只有9个key发生变化,则不管经过多久,这9个key都不会被持久化,因为永远不满足300秒内至少10个key发送变化的条件

因此在save配置项中最好有一条 save XXX 1 的配置兜底,确保redis中所有的变动在一定时间内都能被持久化

如果短时间内变化的次数较多,但根据唯一的那条配置,需间隔300秒后才会进行一次持久化。如果宕机,则会丢失从上一次持久化到宕机这段时间内的修改。也就是说最多会丢失300秒的数据

因此在save配置项中最好有一条 save XXX(小于300秒) XXX(大于10个)的配置,这样在短时间内变更较多时,能提早,更频繁地持久化。如果宕机,最多只会丢失更短时间间隔的数据

怎么实现的?

以下用go代码示例,不过没有特殊的语法,不影响理解

redis维护了两个变量:

  • dirty:在上次bgsave后,执行了多少次修改操作
  • lastsave:上次bgsave的时间

以及配置的规则saveConfig:

type saveConfig struct {
    Change int       // 多少时间内        save 60 3600 中的 3600 
    time   int       // 多少个key发生变化  save 60 3600 中的 60
}

在每次事件循环中尝试每个配置,如果符合某个配置的条件,执行bgsave

func serverCron(){
   // 执行其他操作
   
   interval := time.Now().Sub(lastsave)

   // 尝试每个配置
   for saveConfig := range saveConfigs {
      // 如果符合某个配置的条件,执行bgsave
      if dirty >= saveConfig.Change && interval >= saveConfig.Time {
         bgsave()
         break
      }
   }
}

AOF

与RDB通过快照的方式保存redis中的数据不同,AOF通过保存redis执行的写命令来记录数据库的状态。如果AOF文件记录了有史以来的所有命令,则将这些命令在一个空的redis重播一遍,就可以恢复数据

同步策略

一条写命令从产生到写入AOF文件需经过以下三步:

命令追加文件写入文件同步

一条写命令在被执行完毕后,会被追加到内存缓冲区

接下来就到了事件循环的末尾,一次事件循环的伪代码如下所示:

func eventLoop() {
    for {
        // 处理文件事件,即客户的请求读写,也就是在这里面完成命令追加
        processFileEvents()

        // 处理时间事件,例如定期删除过期键
        processTimeEvents()

        // 根据配置,执行文件写入或文件同步
        flushAppendOnlyFile()
    }
}

在事件循环的开头,会执行文件事件,即客户的请求读写,也就是在这里面完成命令追加

在一次事件循环结束前,redis会根据配置appendfsync的值来来决定怎么处理之前加入到内存缓冲区的aof命令:

  • always:将aof_buf缓冲区中的内容全部写入并同步aof文件

    • 由于每次事件循环都会同步数据到磁盘,总所周知,磁盘的速度比内存慢很多,因此该配置效率最低,但安全性也最高,因为若宕机最多只会丢失一个事件循环的数据
  • everysec:将aof_buf缓冲区中的内容全部写入到aof文件,若当前距离上次同步超过1秒,则执行同步

    • 同步的频率从每次时间循环变为每隔一秒,效率提升不少,同时若宕机最多丢失1秒的数据
  • no:将aof_buf缓冲区中的内容全部写入到aof文件,但不执行同步,何时同步由操作系统决定

    • 从效率上来说是最快的,因此每次都不用等待数据同步到磁盘,但是何时同步数据不可控,有丢失较长时间范围的数据的风险

文件写入和同步:
现代操作系统为了提升效率,用户将一些数据写入磁盘时(文件写入),操作系统通常会将数据暂存于内存缓冲区,等数据填满或超过一定时限后再真正刷入磁盘。同时操作系统也提供了文件同步的函数

值得一提的是,当配置为always时,并不是每写一条命令就同步一次磁盘,而是一次事件循环后同步一次。因为一次事件循环中可能会执行多条命令

生产环境中通常将appendfsync配置为everysec,在保存高性能的同时尽量减少数据丢失

AOF重写

随着程序的运行,aof文件会越来越大,若不加以处理,数据库重启或宕机时使用aof文件来还原的耗时就会越来越长,甚至超出磁盘容量限制。因此redis会定时为aof文件瘦身,使其只保存必要的数据

那什么是不必要的数据呢?

举个例子,假设历史上对list执行了以下6条命令

rpush list "A" // ["A"]

rpush list "B" // ["A","B"]

rpush list "C" // ["A","B","C"]

lpop list // ["B","C"]

lpop list // ["C"]

rpush list "D" "E" // ["C","D","E"]

但这6条命令其实可以用1条命令来替代:

rpush list "C" "D" "E"

这样一来,占用空间和恢复时间都答复减少

进行重写有以下两种方式:

  1. 分析现有aof文件中有关于list的内容,进行重写

  2. 读取内存中list的值,用rpush XXX 这一条命令替换掉aof文件中和list有关的命令

    1. 就像上面的rpush list "C" "D" "E"

很明显,第二种方式实现简单,效率也高,不像第一种方式需要设计复杂的算法来比对,处理aof文件

redis作为单线程应用,如果将aof重写放到主线程中执行,会导致重写期间redis无法处理客户响应

为了避免这种情况,redis将aof文件重写的工作放到子进程中。这么做有以下优点:

  • 主线程能继续对外提供服务,不受aof文件重写的影响
  • 子进程基于fork那一时刻的数据,不受主线程后续操作的影响,这也是fork子进程方式的通用优点

子进程根据内存快照,生成一份新的aof文件

主线程在子进程重写期间,还在源源不断地接收并执行新的写命令,可能在子进程完成重写后,数据库实际的状态,和重写后的aof文件不一致。因此需要将这期间新的写命令追加到重写后的aof文件中,再将重写后的aof文件替换到原来的aof文件,这样aof重写才算完成

为了解决数据不一致问题,redis设置了aof重写缓冲区,在子进程重写期间,新的写命令除了会被写入原aof文件中,还会被写入aof重写缓冲区,这样在子进程重写完毕后,能知道哪些是新命令,将这些新命令追加到重写好的aof文件即可大功告成

在这里插入图片描述

为啥新命令还要写到原aof文件中?保证原来的aof持久化逻辑正常运行,当重写失败时不会对原来产生影响

将新命令追加到重写好的aof文件中不需要在子进程中执行,在主线程中执行即可,原因为

  • 这些新的写命令不会很多,不会对主线程造成太大影响
  • 若再用子进程,还需要考虑怎么合并追加期间的新命令,最终还是需要一个同步操作去合并

混合持久化

单独使用RDB,可能会丢失很多数据,但若单独使用AOF,在恢复数据时相比RDB会慢很多。于是redis 4.0推出了混合持久化,将RDB文件和增量的AOF日志文件放在一起,这里的AOF日志是RDB持久化结束到当前时刻的增量更新日志,通常比较小

在这里插入图片描述

这样的混合持久化方式既有了RDB恢复快的优点,也有AOF不会丢失大量数据的优点

总结

  • RDB通过写时复制技术抓取快照进行持久化,配置保存实际时需考虑到各种情况
  • 根据业务需要配置AOF同步策略,为了避免文件过大,需要进行AOF文件重写
  • 混合持久化方式集成了两者的优点

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

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

相关文章

JAVA实现五子棋小游戏(附源码)

文章目录 一、设计来源捡金币闯关小游戏讲解1.1 主界面1.2 黑棋胜利界面1.3 白棋胜利界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载更多优质源码分享 作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/details/145161039 JA…

无公网IP 实现外网访问本地 Docker 部署 Navidrome

Navidrome 是一款可以在 macOS、Linux、Windows以及 Docker 等平台上运行的跨平台开源音乐服务器应用,它支持传输常见的 MP3、FLAC、WAV等音频格式。允许用户通过 Web 界面或 API 进行音乐库的管理和访问。本文就介绍如何快速在 Linux 系统使用 Docker 进行本地部署…

JS后盾人--JS数组挖掘(少年篇)

数组引用类型分析 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </he…

VirtualBox环境中vscode报错:提取扩展时出错。Failed to fetch

问题现象&#xff1a; VSCode切换到扩展并筛选特色时(为了触发联网)&#xff0c;提示提取扩展时出错。Failed to fetch 拔网线复现不了&#xff0c;完全没有网络VSCode只会提示离线 虚拟机内Edge浏览器访问https://marketplace.visualstudio.com/直接报ERR_CONNECTION_REFUSED…

HTML文章翻页功能

效果展示&#xff1a; 效果原理&#xff1a; 1、引入CDN 2、绘制文章翻页样式&#xff0c;以及自动分段 3、获取窗口宽高&#xff0c;计算出当前文章总分段&#xff0c;并实现分页 4、完整代码 <!DOCTYPE html> <html><head><meta charset"utf-8&qu…

IDEA运行测试函数@Test注解旁边没有运行按钮

如图我想直接运行 testSaveShop 函数进行测试&#xff0c;但是旁边没有运行按钮。 解决办法&#xff1a;测试类需要加上public&#xff0c;系统才能识别到并调用运行。 位置如下&#xff0c;在类和方法都加上 public &#xff0c;然后就会出现运行按钮&#xff1a; 但是如果点…

计算机网络 (38)TCP的拥塞控制

前言 TCP拥塞控制是传输控制协议&#xff08;Transmission Control Protocol&#xff0c;TCP&#xff09;避免网络拥塞的算法&#xff0c;是互联网上主要的一个拥塞控制措施。 一、目的 TCP拥塞控制的主要目的是防止过多的数据注入到网络中&#xff0c;使网络能够承受现有的网络…

使用jupyter notebook没有正常打开浏览器的几种情况解决

迅速记录前期 1.下载 https://www.anaconda.com/products/individual 2.安装 直接默认安装就行 3.打开jupyter notebook 在开始菜单里面可以找到 4.遇到的问题解决 1.运行jupyter notebook&#xff0c;黑窗口自动关了 每次黑窗口迅速的加载完就自己关掉了 也没有打开新…

29、Spark写数据到Hudi时,同步hive表的一些坑

1.hudi的同步hive表没有comment 原以为hudi同步的hive表是根据数据写入的dataframe的schema创建的。就和spark write hive时类似&#xff0c;查看源码后发现不是。 1.1 hudi同步hive的模式 HMS , JDBC , HIVESQL。我这儿常用的是HMS和JDBC 各个同步模式对应的执行器&#x…

wordpress zibll 2025款新页脚-6ke论坛

演示地址&#xff1a;6KE论坛-综合开放交流论坛 [hidecontent type"reply" desc"隐藏内容&#xff1a;评论后查看"] [/hidecontent]

Freeswitch使用media_bug能力实现回铃音检测

利用freeswitch的media bug能力来在智能外呼时通过websocket对接智能中心的声音检测接口&#xff0c;来实现回铃音检测&#xff0c;来判断用户当前是否已响应&#xff0c;拒接&#xff0c;关机等。 1.回铃音处理流程 2.模块源码目录结构 首先新建一个freeswitch的源码的src/a…

基于SpringBoot的企业级工位管理系统【源码+文档+部署讲解】

系统介绍 基于SpringBootVue实现的企业级工位管理系统采用前后端分离架构方式&#xff0c;系统设计了管理员、员工两种角色&#xff0c;系统实现了用户登录与注册、个人中心、员工管理、部门信息管理、工位信息管理、使用情况管理、工位分配管理等功能。 技术选型 开发工具&…

keepalived双机热备(LVS+keepalived)实验笔记

目录 前提准备&#xff1a; keepalived1&#xff1a; keepalived2&#xff1a; web1&#xff1a; web2&#xff1a; keepalived介绍 功能特点 工作原理 应用场景 前提准备&#xff1a; 准备4台centos&#xff0c;其中两台为keepalived&#xff0c;两台为webkeepalive…

【Linux】12.Linux进程概念(1)

文章目录 1. 冯诺依曼体系结构2. 操作系统(Operator System)概念设计OS的目的胆小的操作系统定位如何理解 "管理"总结 3. 进程基本概念task_struct-PCB的一种task_ struct内容分类组织进程查看进程通过系统调用获取进程标示符通过系统调用创建进程-fork初识 1. 冯诺依…

LabVIEW 程序中的 R6025 错误

R6025错误 通常是 运行时库 错误&#xff0c;特别是与 C 运行时库 相关。这种错误通常会在程序运行时出现&#xff0c;尤其是在使用 C 编译的程序或依赖 C 运行时库的程序时。 ​ 可能的原因&#xff1a; 内存访问冲突&#xff1a; R6025 错误通常是由于程序在运行时访问无效内…

03JavaWeb——Ajax-Vue-Element(项目实战)

1 Ajax 1.1 Ajax介绍 1.1.1 Ajax概述 我们前端页面中的数据&#xff0c;如下图所示的表格中的学生信息&#xff0c;应该来自于后台&#xff0c;那么我们的后台和前端是互不影响的2个程序&#xff0c;那么我们前端应该如何从后台获取数据呢&#xff1f;因为是2个程序&#xf…

2024 京东零售技术年度总结

每一次回望&#xff0c;都为了更好地前行。 2024 年&#xff0c;京东零售技术在全面助力业务发展的同时&#xff0c;在大模型应用、智能供应链、端技术、XR 体验等多个方向深入探索。京东 APP 完成阶段性重要改版&#xff0c;打造“又好又便宜”的优质体验&#xff1b;国补专区…

Apache搭建https服务器

Apache搭建https服务器 REF: 使用OpenSSL自建一个HTTPS服务

XML在线格式化 - 加菲工具

XML在线格式化 打开网站 加菲工具 选择“XML 在线格式化” 输入XML&#xff0c;点击左上角的“格式化”按钮 得到格式化后的结果

BO-SVM贝叶斯算法优化支持向量机的数据多变量时间序列预测

BO-SVM贝叶斯算法优化支持向量机的数据多变量时间序列预测 目录 BO-SVM贝叶斯算法优化支持向量机的数据多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于BO-SVR贝叶斯算法优化支持向量机的数据多变量时间序列预测&#xff0c;加入5折交叉验…