当前位置: 首页 > news >正文

【Redis】持久化与事务

文章目录

  • 1. 持久化
    • 1.1 RDB(定期)
      • 1.1.1 触发方式
      • 1.1.2 触发流程
    • 1.2. AOF(实时)
      • 1.2.1 设置AOF
      • 1.2.2 刷新策略
      • 1.2.3 重写机制
  • 2. 事务
    • 2.1 redis事务概念
    • 2.2 事务操作

在这里插入图片描述

Mysql有几个特性:

  • 原子性
  • 一致性
  • 隔离性,redis是串行的,自带隔离性
  • 持久性,redis的持久化跟这个是一回事

1. 持久化

所以,要想办法将redis保存在内存上的的数据存在磁盘上;但是直接将数据存到磁盘上,是不是违反了redis快的特性了呢? - - 是的

为了达到快、持久的特性,redis会在内存、磁盘上均存储数据,并且两份数据理论上应该相同;将数据从内存写入到硬盘有不同的策略。

代价:消耗了更多的空间

Redis ⽀持RDB(redis database)和AOF(append only file)两种持久化机制,持久化功能有效地避免因进程退出造成数据丢失问题,当下次重启时利⽤之前持久化的⽂件即可实现数据恢复当查询数据时,依旧是从内存中查找

1.1 RDB(定期)

1.1.1 触发方式

RDB策略定期的将redis内存中的数据,形成一个“快照”,写入到硬盘中。

  1. 手动触发
  • save:会阻塞其它redis命令,不建议使用
  • bgsave:后台运行(fork),子进程进行生成快照,写文件的工作
  1. 自动触发

配置文件中设置,修改配置文件后,一般需要重启服务器

两个条件都满足,才执行

其中,save ""是关闭自动生成

在这里插入图片描述

1.1.2 触发流程

手动触发的执行流程:

在这里插入图片描述
RDB文件的位置:
在这里插入图片描述
在这里插入图片描述

保存:RDB⽂件保存再dir配置指定的⽬录(默认/var/lib/redis/)下,⽂件名通过dbfilename配置(默认dump.rdb)指定。
可以通过执⾏config setdir {newDir}config setdbfilename {newFilename} 运⾏期间动态执⾏,当下次运⾏时RDB⽂件会保存到新⽬录。

至始至终,RDB文件只有一个

压缩:Redis默认采⽤LZF算法对⽣成的RDB⽂件做压缩处理,压缩后的⽂件远远⼩于内存大小,默认开启,可以通过参数config set rdbcompression{yes|no}动态修改。

校验:如果Redis启动时加载到损坏的RDB⽂件会拒绝启动。这时可以使⽤Redis提供的redis-check-dump⼯具检测RDB⽂件并获取对应的错误报告。
在这里插入图片描述

测试一下:

在这里插入图片描述

redis生成快照时,不仅仅是手动触发,也可以自动触发

  • 配置文件中设置触发条件
  • redis服务器正常关闭时,会触发
  • 执行主从复制时,主节点也会自动生成rdb快照,然后把rdb快照文件内容传输给从节点(后面讲)

若异常退出(kill - 9 、断电),不会保存

bgsave 操作流程是创建子进程,子进程完成持久化操作,持久化速度太快了(数据少),难以观察到子进程.

持久化会把数据写入到新的文件中,然后使用新的文件替换旧的文件,这个是容易观察到的;可以使用 linux 的 stat 命令,査看文件的 inode 编号
在这里插入图片描述

如果直接使用 save 命令,此时是不会触发子进程 & 文件替换逻辑;save 就直接在当前进程中,往同一个文件中写入数据了

RDB的优缺点

  • RDB是⼀个紧凑压缩的⼆进制⽂件,代表Redis在某个时间点上的数据快照。⾮常适⽤于备份,全量复制等场景。
    • ⽐如每6⼩时执⾏bgsave备份,并把RDB⽂件复制到远程机器或者⽂件系统中(如hdfs)⽤于灾备。
  • Redis加载RDB恢复数据远远快于AOF的⽅式
    • 因为其是使用二进制方式组织数据的
  • RDB⽅式数据没办法做到实时持久化/秒级持久化
    • 因为bgsave每次运⾏都要执⾏fork创建⼦进程,属于重量级操作,频繁执⾏成本过⾼。
  • RDB⽂件使⽤特定⼆进制格式保存,Redis版本演进过程中有多个RDB版本,兼容性可能有⻛险。

1.2. AOF(实时)

1.2.1 设置AOF

AOF持久化:以独⽴⽇志的⽅式记录每次写命令,重启时再重新执⾏AOF⽂件中的命令达到恢复数据的⽬的。

AOF的主要作⽤是解决了数据持久化的实时性,⽬前已经是Redis 持久化的主流⽅式。

当开启aof的时候,就会读取aof这个文件的内容,用来恢复数据(此时rdb就不生效了)

  • 开启AOF功能需要设置配置:appendonly yes,默认不开启。
  • AOF⽂件名通过appendfilename 配置(默认是appendonly.aof)设置。保存⽬录同RDB持久化⽅式⼀致,通过dir配置指定。
  • AOF的⼯作流程操作:命令写⼊(append)、⽂件同步(sync)、⽂件重写(rewrite)、重启加载(load)

在这里插入图片描述

appendonly开启后,自动保存
AOF是一个文本文件,redis的每一次操作,都会被记录到文件中
在这里插入图片描述

1.2.2 刷新策略

引入AOF后,redis既要写内存,又要写磁盘,它的速度会不会受影响呢? - - 并没有
在这里插入图片描述

  1. 所有的写⼊命令会追加到aof_buf(缓冲区)中。
  2. AOF缓冲区根据对应的策略向硬盘做同步操作
  3. 随着AOF⽂件越来越⼤,需要定期对AOF⽂件进⾏重写,达到压缩的⽬的。
  4. 当Redis服务器启动时,可以加载AOF⽂件进⾏数据恢复

AOF过程中为什么需要aof_buf这个缓冲区?Redis使⽤单线程响应命令,如果每次写AOF⽂件都直接同步硬盘,性能从内存的读写变成IO读写,必然会下降。先写⼊缓冲区可以有效减少IO次数,同时,Redis还可以提供多种缓冲区同步策略,让⽤⼾根据⾃⼰的需求做出合理的平衡。

redis给出了一些缓冲区刷新的策略,根据不同的场景供我们选择
在这里插入图片描述

1.2.3 重写机制

随着命令不断写⼊AOF,⽂件会越来越⼤,为了解决这个问题,Redis引⼊AOF重写机制压缩⽂件体积

AOF⽂件重写是把Redis进程内的数据转化为写命令同步到新的AOF⽂件(剔除、合并一些操作,从而达到“瘦身的目的”

重写后的AOF为什么可以变⼩?有如下原因:

  • 进程内已超时的数据不再写⼊⽂件。
  • 旧的AOF中的⽆效命令,例如del、hdel、srem等重写后将会删除,只需要保留内存中数据的最终版本
  • 多条写操作合并为⼀条,例如lpush key a、lpush key b、lpush key c从可以合并为lpush key a b c
  • 较⼩的AOF⽂件⼀⽅⾯降低了硬盘空间占⽤,⼀⽅⾯可以提升启动Redis时数据恢复的速度

AOF重写过程可以手动触发和⾃动触发:

  • 手动触发:调⽤bgrewriteaof命令。
  • 自动触发:根据auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage参数确定⾃动触发时机。
    • auto-aof-rewrite-min-size:表⽰触发重写时AOF的最小文件大小,默认为64MB。
    • auto-aof-rewrite-percentage:代表当前AOF占用大小相⽐较上次重写时增加的⽐例

AOF重写流程

如果当前进程正在执⾏AOF重写,请求不执⾏;如果当前进程正在执⾏bgsave操作,重写命令延迟到bgsave完成之后再执⾏。

子进程只需要把内存中当前的数据获取出来,以 AOF 的格式写入到一个新的 AOF 文件中
(内存中的数据的状态,就已经相当于是把 AOF 文件结果整理后的模样了)在这里插入图片描述

此处子进程写数据的过程,非常类似于 RDB 生成一个镜像快照

  • 只不过 RDB 这里是按照二进制的方式来生成的,
  • AOF 重写,则是按照 AOF 这里要求的文本格式来生成的,
  • 二者都是为了把当前内存中的所有数据状态记录到文件中!!

启动时数据恢复
当Redis启动时,会根据RDB和AOF⽂件的内容,进⾏数据恢复
在这里插入图片描述
混合持久化模式:按照aof的方式,每一个请求/操作,都记录到文件中;在触发aof重写后,就会把当前的内存状态按照rdb二进制的格式写入到新的aof文件中,后续在进行操作,仍然是按照aof文本的方式追加在后面

在这里插入图片描述

RDB与AOF的对比:

  1. RDB视为内存的快照,产⽣的内容更为紧凑,占⽤空间较小,恢复时速度更快。但产⽣RDB的开销较⼤,不适合进⾏实时持久化,⼀般⽤于冷备和主从复制。
  2. AOF视为对修改命令保存,在恢复时需要重放命令。并且有重写机制来定期压缩AOF⽂件。
  3. RDB和AOF都使⽤fork创建⼦进程,利⽤Linux⼦进程拥有⽗进程内存快照的特点进⾏持久化,尽可能不影响主进程继续处理后续命令。

可能出现的面试题:

  1. redis为什么持久化?有哪些方式?
  2. RDB与AOF的区别,各自有什么优势?
  3. RDB文件的生成流程,以及AOF重写的流程

2. 事务

2.1 redis事务概念

Redis的事务和MySQL事务的区别:

  • 弱化的原⼦性:redis没有"回滚机制",只能做到这些操作"批量执行",不能做到"⼀个失败就恢复到初始状态"
  • 不保证⼀致性:不涉及"约束",也没有回滚。
    • MySQL的⼀致性体现的是运⾏事务前和运⾏后,结果都是合理有效的,不会出现中间⾮法状态
  • 不需要隔离性:也没有隔离级别,因为不会并发执⾏事务(redis单线程处理请求).
  • 不需要持久性:redis是保存在内存的,是否开启持久化,是redis-server⾃⼰的事情,和事务⽆关

Redis 事务本质上是在服务器上搞了⼀个"事务队列",每次客⼾端在事务中进⾏⼀个操作,都会把命令先发给服务器,放到"事务队列"中,但是并不会⽴即执⾏,⽽是会在真正收到EXEC命令之后才真正执⾏队列中的所有操作

因此,Redis的事务的功能相⽐于MySQL来说,是弱化很多的,只能保证事务中的这⼏个操作是"连续的",不会被别的客⼾端"加塞",仅此⽽已。

redis为什么不像mysql一样呢? - - 所需空间、时间的代价太大

2.2 事务操作

  1. MULTI

开启⼀个事务,执⾏成功返回OK

  1. EXEC

真正执⾏事务

  1. DISCARD

放弃当前事务,此时直接清空事务队列,之前的操作都不会真正执⾏到

在这里插入图片描述

当开启事务,并发送多个命令后,此时服务区器重启了,此时的效果就等同于discard.

  1. WATCH

在执⾏事务的时候,如果某个事务中修改的值,被别的客⼾端修改了,此时就容易出现数据不⼀致的问题

# 客⼾端1 先执⾏
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key 100
QUEUED# 客⼾端2 再执⾏
127.0.0.1:6379> set key 200
OK# 客⼾端1 最后执⾏
127.0.0.1:6379> EXECOK

此时,key的值是多少呢??
从输⼊命令的时间看,是客⼾端1先执⾏的setkey100,客⼾端2后执⾏的setkey200,但是从实际的执⾏时间看,是客⼾端2先执⾏的,客⼾端1后执⾏的

127.0.0.1:6379> get key 
"100"

这个时候就容易引起歧义,因此,即使不保证严格的隔离性,⾄少也要告诉⽤⼾,当前的操作可能存在⻛险, watch命令就是⽤来解决这个问题的,watch在该客⼾端上监控⼀组具体的key

  • 当开启事务的时候,如果对watch的key进⾏修改,就会记录当前key的"版本号".(版本号是个简单的整数,每次修改都会使版本变⼤,服务器来维护每个key的版本号情况)
  • 在真正提交事务的时候,如果发现当前服务器上的key的版本号已经超过了事务开始时的版本号,就会让事务执⾏失败。(事务中的所有操作都不执⾏).

客户端1先执行

127.0.0.1:6379> watch k1      # 开始监控k1
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 100  #进⾏修改,从服务器获取k1的版本号是0.记录k1的版本号.(还没真修改呢, 版本号不变)
QUEUED
127.0.0.1:6379> set k2 1000     
QUEUED

客⼾端2再执行

127.0.0.1:6379> set k1 200     # 修改成功, 使服务器端的k1 的版本号 0 -> 1
OK

客⼾端1再执行

127.0.0.1:6379> EXEC          
# 真正执⾏修改操作, 此时对⽐版本发现, 客⼾端的 k1 的版本号是 0, 
#服务器上的版本号是 1, 版本不⼀致! 说明有其他客⼾端在事务中间修改了 k1 !!! 
(nil)
127.0.0.1:6379> get k1
"200"
127.0.0.1:6379> get k2
(nil)

此时说明事务已经被取消了,这次提交的所有命令都没有执行。

  1. UNWATCH

取消对key的监控.

在这里插入图片描述

相关文章:

  • 电容的基本介绍
  • iNeuOS工业互联网操作系统,集成DeepSeek大模型应用
  • C#串口通信
  • 前端面试每日三题 - Day 28
  • LeetCode第284题 - 窥视迭代器
  • 1688 开放平台 API 全解析:商品详情实时数据采集接口开发手册
  • 存储器:DDR和独立显卡的GDDR有什么区别?
  • 数据透视表控件DHTMLX Pivot v2.1发布,新增HTML 模板、增强样式等多个功能
  • Pyinstaller编译EXE及反编译
  • 解决方案:ValueError: setting an array element with a sequence.
  • 主成分分析(PCA)是什么?简易理解版
  • web 自动化之 selenium+webdriver 环境搭建及原理讲解
  • 第三天 车联网云架构
  • CAS、CAS自旋、CAS自旋锁、CLH锁与Java AQS:深入理解并发编程核心机制
  • stable diffusion的attention-map:提取和可视化跨注意力图
  • DRAM详解
  • 【Electron】electron-vue 借助 element-ui UI 库助力桌面应用开发
  • MIST:一键解锁 macOS 历史版本,旧系统安装不再难!
  • 学习黑客 MAC 地址深入了解
  • 问题 | 低空经济未来发展前景机遇及挑战
  • 女子应聘文员被说“太丑”?官方回应:有关部门启动核查处置
  • 哪条线路客流最大?哪个站点早高峰人最多?上海地铁一季度客流报告出炉
  • 国家统计局向多省份反馈统计督察意见
  • 2000多年前的“新衣”长这样!马王堆文物研究新成果上新
  • 会谈时间迟迟未定、核心议题存在分歧,俄乌“土耳其谈判”一波三折
  • 国税总局上海市税务局通报:收到王某对刘某某及相关企业涉税问题举报,正依法依规办理