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

【Redis】持久化(RDB和AOF)和事务

   🔥个人主页: 中草药

🔥专栏:【中间件】企业级中间件剖析


一、持久化

对于数据的存储而言,为保证速度快,数据得在内存中,但为了持久,数据还得存在硬盘之中,Redis 的持久化机制是其高可靠性的核心,主要用于在重启或崩溃后恢复数据。它提供两种主要持久化方式:RDB(Redis Database) 和 AOF(Append-Only File),以及从 4.0 版本开始支持的 混合持久化

RDB(Redis Database 快照持久化)

工作原理

  • 基于快照:RDB 通过定期生成内存数据的二进制快照(Snapshot)保存到磁盘(默认文件为 dump.rdb)。

  • 触发机制

    • 手动触发:通过 SAVE(执行时,Redis会阻塞主线程,可能会导致keys *的效果,一般不建议使用)BGSAVE(BackGround ,非阻塞,Redis通过后台子进程处理)命令。

    • 自动触发:根据配置文件中的 save 规则(如 save 900 1 表示 900 秒内至少 1 个键被修改时触发)。(生成快照是一个成本比较高的操作,不能让这个操作频繁执行)

自动触发除此之外有以下这几种方式:

1、正常流程重新启动redis服务器,通过shutdown命令(redis里的一个命令)关闭服务器,也会触发(service redis-server restart),但异常重启(kill -9 或 服务器掉电)来不及生成RDB,会出现数据丢失

2、redis进行主从复制的时候,主节点也会自动生成RDB快照,然后把rdb文件内容传输给节点

  • bgsave:使用 BGSAVE 时,Redis 首先会判定当前是否存在其他正在工作的子进程,如果没有主进程会 fork 一个子进程,子进程负责将内存数据写入临时 RDB 文件生成快照,父进程将继续接受客户端的请求,继续正常提供服务,子进程完成整体的持久化过程后替换旧文件,并通知父进程,父进程更新一些统计信息,子进程结束销毁

fork

Linux 的 fork() 是创建新进程的核心系统调用,它会创建一个与父进程几乎完全相同的子进程,包括代码段、数据段、堆栈、文件描述符、信号处理等。

子进程拥有独立的进程空间,但初始时与父进程共享物理内存(通过写时复制,Copy-On-Write, COW 技术优化性能)。

redis生成的rdb文件,是存放在 redis 的工作目录之中,可在 redis 的工作目录

rdb的镜像文件 

redis提供了检查rdb文件的工具 

优点

  • 紧凑高效:RDB是一个紧凑压缩的二进制文件,体积小,适合备份、全量复制和灾难恢复。

  • 快速恢复:加载 RDB 文件的速度远快于 AOF。

  • 低性能影响:生成快照由子进程处理,主进程几乎不受影响(除 fork 时的短暂延迟)。

缺点

  • 数据丢失风险:若两次快照间发生故障,会丢失最后一次快照后的数据。

  • 大内存开销:RDB无法做到实时持久化,秒级持久化,fork 子进程时,属于重量级操作,若数据集过大,可能导致主进程短暂阻塞(尤其在虚拟内存不足时)。

  • 兼容性风险:RDB文件使用特定的二进制格式保存,Redis版本演进过程中有过多个RDB版本,兼容性存在风险

配置示例

修改配置后,需要重新启动服务器 service redis-server restart

save 900 1      # 900秒内至少1个键修改则触发
save 300 10     # 300秒内至少10个键修改
save 60 10000   # 60秒内至少10000个键修改
save ""         # 关闭自动生成快照
stop-writes-on-bgsave-error yes  # 快照失败时停止写入
rdbcompression yes               # 压缩RDB文件
rdbchecksum yes                  # 校验数据完整性

 rdb文件时二进制的,如果redis在启动时使用这个文件,造成的后果是不可预期的,可能redis的服务器可以启动,得到的数据可能正确,也可能有问题,也有更大的可能redis服务器直接启动失败。这时我们需要用到redis提供的检查rdb文件的工具redis-check-rdb 


AOF(Append Only File 日志追加持久化)

工作原理

AOF默认一般是关闭状态,当AOF启动的时候,redis不再读取 RDB 的内容,手动修改配置文件打开

引入AOF操作之后,即使既要写内存也要写硬盘,也并没有影响到redis处理请求的速度

1、AOF机制并非直接让工作线程把数据写入硬盘,而是先写入一个内存中的缓冲区(因此,如果缓冲区没来得及写入硬盘,也会发生数据丢失),积累一波后,再统一写入硬盘之中,降低写硬盘的次数

2、AOF append是每次把新的操作写入原有文件的末尾,属于顺序写入,在硬盘上读写数据,顺序读写速度相对较快,随机访问的速度比较慢

记录写操作:以文本日志形式记录所有写命令(如 SETDEL),保存到 appendonly.aof 文件。

同步策略

频率越高,数据可靠性越高,性能越低

  • always:每次写命令都同步到磁盘(最安全,性能最低)。

  • everysec:每秒同步一次(默认,平衡安全与性能)。

  • no:由操作系统决定同步时机(性能最高,风险最大)。

AOF 重写机制(Rewrite):

  • 解决 AOF 文件膨胀问题。通过生成新 AOF 文件,删除冗余命令(如多次修改同一键,仅保留最终状态)到达给文件瘦身的目的。

  • 触发方式:手动执行 BGREWRITEAOF 或根据配置自动触发如 auto-aof-rewrite-percentage 100 表示文件增长 100% 时触发 auto-aof-rewrite-min-size 64mb 表示触发重写时AOF最小文件大小)。

  • 重写流程:重写时,不关心aof文件原本有什么,只关心内存中最终的数据状态(此时的状态已经相当于AOF文件结果整理后的摸样)再fork之后,父进程会把新来的请求同时写入两个缓冲区,其中的aof_rewrite_buf缓冲区,专门放fork之后的数据,子进程这边,把aof数据写完之后,会通过信号通知一下进程,父进程会把aof_rewrite_buf缓冲区的内容写进新的AOF文件(父进程同时往旧的AOF文件写数据是因为考虑到极端情况,保证数据的完整性)

如果在执行  BGREWRITEAOF  操作时,发现redis已经在进行AOF重写了,此时不会再执行操作而是直接返回,而如果此时redis正在生成RDB快照,aof重写操作就会等待,等待RDB快照生成完毕之后,再执行AOF重写

优点

  • 数据更安全:最多丢失 1 秒数据(默认 everysec 策略)。

  • 可读性强:AOF 文件为文本格式,便于人工分析。

  • 灵活恢复:支持修复损坏的 AOF 文件(如使用 redis-check-aof 工具)。

缺点

  • 文件体积大:AOF 文件通常比 RDB 大。

  • 恢复速度慢:重放所有命令恢复数据,耗时长。

  • 写性能开销:高频写入场景下,AOF 可能影响吞吐量。 

当redis上同时存在aof文件和rdb快照时,以rdb快照为主


混合持久化(Redis 4.0+)

工作原理

  • 结合 RDB 和 AOF:在 AOF 重写时,新生成的 AOF 文件前半部分是 RDB 格式的快照数据,后半部分是增量 AOF 命令。

  • 恢复流程:先加载 RDB 快照,再执行后续 AOF 命令,兼顾速度和数据完整性。

配置

aof-use-rdb-preamble yes  # 启用混合持久化(需同时启用AOF)

优点

  • 快速恢复:RDB 快照加速数据加载。

  • 低数据丢失:AOF 记录增量命令,保障数据安全。


二、事务

Redis的事务机制提供了一种将多个命令打包并按顺序执行的途径,但其实现与传统关系型数据库的事务(如ACID特性)有显著差异。以下是对Redis事务的详细解析:


与传统数据库事务的对比

特性Redis事务传统数据库(如MySQL)
原子性部分保证(运行时错误不中断)完全保证(ACID)
隔离性不涉及隔离性,单线程保证指令操作串行化执行支持多种隔离级别(如读提交、可重复读)
回滚机制不支持支持通过ROLLBACK回滚
错误处理分语法错误(拒绝执行)和运行时错误(继续执行)事务内错误触发回滚

原子性:Redis事务的原子性较。命令队列在EXEC时整体执行(中途不会穿插其他命令),但运行时错误不会回滚。

隔离性:由于Redis单线程模型,事务执行期间不会被其他命令打断,具备隔离性(类似可串行化)。

无回滚机制:设计哲学追求简单高效,故不支持回滚,需开发者自行处理错误。

提到Redis的原子性是存在争议的,由于MySQL存在回滚,他能保证多个操作打包在一起,要不全都执行成功,要么全都不执行,当事务中存在操作执行失败,进行回滚。而Redis只能保证将多个操作按事务的方式执行,如果出现失败也不会发生回滚的操作。所以存在说法Redis不具备原子性

基本命令

Redis事务通过以下命令管理:

  • MULTI:开启事务,之后的命令被放入队列,直到执行EXEC或DISCARD。

  • EXEC:执行事务队列中的所有命令。

  • DISCARD:取消事务,清空队列中的命令。(若开启事务,发生服务器的重启,效果等同于discard)

  • WATCH:监视一个或多个键,用于实现乐观锁(CAS操作)。

  • UNWATCH:取消对所有键的监视。

示例流程

> WATCH key1       # 监视键key1
> MULTI            # 开启事务
> SET key1 value1  # 命令入队
> GET key1         # 命令入队
> EXEC             # 执行事务

若在WATCHEXEC前,key1被其他客户端修改,事务将失败,返回(nil)


WATCH与乐观锁

  • 作用WATCH监视键,若事务执行前这些键被修改,事务将失败。需结合重试机制实现乐观锁。

  • 典型应用场景:余额扣减。

乐观锁预期锁冲突概率低,假设在大多数情况下,并发操作不会发生冲突,只有在更新数据时才去检查是否有冲突。就好像它总是乐观地认为大家都能 “和平共处”,不会出现数据争抢的情况。

客户端调用 WATCH

  • 例如 WATCH balance,客户端将 balance 的当前版本号保存到自己的监视列表中。

  • Redis 服务端会将该客户端加入 balance 键的监视者列表(一个链表结构,记录所有监视该键的客户端)。

客户端开启事务(MULTI

  • 后续所有命令会缓存在事务队列中,但不会立即执行。

其他客户端的操作

  • 如果在事务提交前,其他客户端修改了 balance(如 SET balance 100),balance 的版本号会递增。

  • Redis 会遍历 balance 的监视者列表,标记所有监视该键的客户端的事务为失效(即事务提交时会失败)。

客户端提交事务(EXEC

  • 校验阶段:Redis 检查该客户端所有 WATCH 的键的当前版本号是否与最初记录的版本号一致。

    • 一致:执行事务队列中的命令,更新键的版本号,并返回所有命令的结果。

    • 不一致:直接放弃事务,返回 nil(事务失败)。

这样的设定思想有点类似于CAS里面的ABA问题


烈火试真金,逆境试强者。--塞内加

🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀

以上,就是本期的全部内容啦,若有错误疏忽希望各位大佬及时指出💐

  制作不易,希望能对各位提供微小的帮助,可否留下你免费的赞呢🌸 


http://www.kler.cn/a/580681.html

相关文章:

  • 平安养老险陕西分公司启动315金融消费者权益保护教育宣传活动
  • 密码学 网络安全 科普 网络安全密码技术
  • MFC 项目:简易销售系统实践
  • 【HeadFirst系列之HeadFirst设计模式】第18天之深入解析解释器模式:从原理到实战
  • LLaMA-Factory训练DeepSeek大模型+本地部署
  • PPT内视频播放无法播放的原因及解决办法
  • 【Godot】@export_multiline
  • 【性能测试】Jmeter下载安装、环境配置-小白使用手册(1)
  • 《基于深度学习的图像识别技术在医学影像分析中的应用研究》
  • 智能焊机监测系统:打造工业安全的数字化盾牌
  • C#工业上位机实时信号边沿检测实现
  • Liunx——动静态库
  • Android Broadcast广播封装
  • 基于深度学习的中文文本情感分析系统
  • 我与DeepSeek读《大型网站技术架构》(8)- 网站应用攻击与防御
  • 智能化时代,美容院如何借助科技实现高效运营?
  • 行为级建模
  • React框架连续解构赋值详细解读
  • Nest.js全栈开发终极实践:TypeORM+微服务+Docker构建高可用企业级应用
  • LeetCode --- 439周赛