【Redis】持久化

发布于:2025-07-18 ⋅ 阅读:(12) ⋅ 点赞:(0)

在这里插入图片描述

持久化

在计算机组成原理中我们学到,RAM 是掉电丢失数据的,而 ROM 则是掉电不丢失。RAM 对应内存,ROM 对应磁盘。持久化就是将内存中的数据保存在磁盘上,这样在关机或者应故障重启后,数据才可以从磁盘上重新被读取,加载到内存

而 Redis 的特点之一就是将数据保存在内存中,所以读写效率高,但保存在内存中就有掉电丢失的风险,所以 Redis 也是需要对数据进行持久化的。
为了保证速度快,数据还是需要在内存中,但为了持久,还需要存储在磁盘上。当要插入一个新的数据时,该数据会存储在内存和硬盘中,而当查询数据时,直接从内存读取,硬盘的数据只是在 Redis 重启的时候,用于恢复内存中的数据

持久化策略

虽然需要对数据进行持久化策略,但不是插入一个数据就进行持久化,写入磁盘,这样势必会导致效率的降低,Redis 有两种策略来决定何时写磁盘,如何写磁盘

  1. RDB => Redis DataBase
  2. AOF => Append Only File

简单来说
RDB 是定期备份,比如,每个月把电脑上的资料,整体备份到一个备份磁盘
AOF 是实时备份,只要下载了一份资料,就立即拷贝一份到备份磁盘

RDB

RDB 会定期把 Redis 内存的数据,写入磁盘,生成一个快照。后续 Redis 重启,就可以根据快照恢复内存的数据

RDB文件,即快照,是二进制文件,把内存的数据以压缩的形式保存,需要消耗一定的CPU资源,但节省空间,写入和加载解析较为方便,速度快

MySQL 也有快照的概念,二者本质相同,都是记录某一时刻下的数据或状态。

定期策略

定期,又有两种方式:

(1). 手动触发:通过 redis 客户端,执行命令触发快照生成

  • save:执行 save 后,redis 会全力进行 “快照生成” 操作,此时会阻塞 redis 其他客户端的命令,一般不建议使用 save
  • bgsave:background save,不会影响 redis 服务器处理其他客户端的请求和命令,通过使用多进程实现

savebgsave 的区别就是 save 是阻塞服务,在当前进程对 rdb 快照进行覆盖写;而 bgsave 是创建子进程,生成新的 rdb 快照,完成后再进行替换

(2). 自动触发

在 Redis 的配置文件中,可以设置每隔多长时间 / 每产生多少次修改,触发快照生成

bgsave

bgsave 是主流的 RDB 持久化方式,下图为运作流程:

在这里插入图片描述

  1. 执行 bgsave 命令,Redis 服务器的父进程判断当前是否已经有正在执行的子进程,如 RDB / AOF 子进程,如果存在,则直接返回
  2. 父进程执行 fork 创建子进程,fork 过程父进程会阻塞,可以通过 info stats 命令查看 last_fork_usec 选项,获取最近一次 fork 的耗时,单位为微秒
  3. 父进程 fork 完成后,bgsave 返回 Background saving start,父进程不再阻塞,可以继续响应其他命令
  4. 子进程共享父进程的文件描述符,缓冲区等资源,对当前内存数据创建 RDB 文件,生成临时快照文件,完成后再对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成 RDB 的时间,对应 info 统计的 rdb_last_save_time
  5. 子进程发送信号通知父进程操作完成,父进程更新统计信息

在这里插入图片描述

自动触发

自动触发,可以通过命令或者配置文件进行配置
redis 的配置文件一般为 /etc/redis/redis.conf

.rdb 文件的命名如下:

在这里插入图片描述
.rdb 文件存放的路径配置如下:

在这里插入图片描述

因为是二进制文件,所以直接查看会有乱码

在这里插入图片描述

当 rdb 文件损坏或格式错误时,redis 服务器重启时,尝试加载 rdb 文件失败,就可能会加载数据失败,甚至无法启动 redis 服务器

Redis 也提供了检查 rdb 文件的工具,在/usr/bin 目录下

在这里插入图片描述

其中, redis-check-rdb 可用于检查 rdb 文件是否有误


自动触发主要有种:

  1. 通过配置文件的 save 设置,执行 M 时间内,修改 N 次。如果配置为 save "" 代表关闭自动生成快照
  2. 通过 shutdown 命令(redis 客户端命令) 关闭服务器,也会触发(service redis-server restart)
  3. redis 进行主从复制的时候,主节点也会自动生成 rdb 快照,然后把 rdb 快照文件内容传输给从节点

PS:flushall(redis 命令)也会触发 RDB

配置文件的默认配置如下:

在这里插入图片描述

分别表示:
从一个时间点开始:

  • save 900 1:之后的900秒(15分钟),至少有1条修改
  • save 300 10:之后的300秒(5分钟),至少有10条修改
  • save 60 10000:之后的60秒(1分钟),至少有10000条修改

以上条件满足一个都会进行 rdb 持久化,生成新的快照

注意:上述时间不是期间内达到要求就会生成新的快照,而是在指定的时间后,达到修改条数才会操作。
比如距离上次生成快照,进行了15次修改,那么在距离上次300秒后才会生成新的快照

缺点

  1. 数据不一致:因为生成一次 rdb 快照有比较高的成本,所以不能让其操作太频繁,但也正是因为不能太频繁,导致快照的数据,和当前实时的数据可能会存在偏差。AOF实时备份则解决了这个问题
  2. 数据可能丢失:因为定期备份,当没有达到 save 配置的要求时,如果 redis 服务器不正常退出,则并没有生成新的快照,这部分数据就会丢失
  3. 因为 RDB 保存的是二进制文件,当文件损坏时,redis 可能无法启动,或者启动后加载了错误的数据。当 redis 服务挂了的时候,可以查看 redis 的日志,一般在/var/log/redis/redis-server.log

总的来说,RDB 具有以下优缺点

优点

  • RDB 是⼀个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份全量复制等场景。比如每 6 小时执行 bgsave 备份,并把 RDB 文件复制到远程机器或者文件系统中(如 hdfs )用于灾备
  • Redis 加载 RDB 恢复数据远远快于 AOF 的方式

缺点

  • RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 运行要执行 fork 创建子进程,属于重量级操作,频繁执行成本过高
  • RDB 文件使用特定二进制格式保存,Redis 版本演变过程有多个 RDB 版本,兼容性可能有风险

AOF

AOF(Append Only File)持久化:以独立日志的方式记录每次的写命令,重启时再重新执行 APF 文件的命令达到恢复数据的目的。AOF 主要作用是解决数据持久化的实时性,目前是 Redis 持久化的主流方式

工作流程

首先需要通过配置文件开启 AOF,默认是不开启的,即 appendonly no,改为 yes 开启

在这里插入图片描述

AOF 文件名通过 appendfilename 配置,保存目录同 RDB 持久化的 .rdb 一致,通过 dir 配置指定

当开启 AOF 后,就不会使用 RDB 了,Redis 在使用持久化的时候会先判断 AOF 是否开启,开启即使用 AOF,否则使用 RDB


AOF 工作流程操作:命令写入(append)、文件同步(sync)、文件重写(rewrite)、重启加载(load)

在这里插入图片描述

  1. 所有的写入命令会追加到 aof_buf (内存缓冲区)中
  2. AOF 缓冲区根据对应的策略向硬盘座同步操作
  3. 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,合并冗余的操作,达到压缩的目的
  4. 当 Redis 服务启动时,加载 AOF 文件进行数据恢复

AOF 命令写入的内容是文本协议格式,例如 set hello world,在 aof_buf 会追加如下文本:

*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n

使用的 Redis 定义的格式协议,可能是文本协议具备较好的兼容性,实现简单,可读性好

因为 Redis 为单线程,如果每次写 AOF 都是写磁盘,那性能会很差,所以采用先写入缓冲区 aof_buf,减少 IO 次数。

同时 Redis 还提供多种缓冲区同步策略,由配置文件的 appendfsync 控制

配置 说明 特点
always 命令写入 aof_buf 调用 fsync 同步,完成后返回 频率高、实时性好、性能差
everysec 命令写入 aof_buf 后只执行 write 操作,不进行 fsync。每秒由同步线程进行 fsync 频率中、实时性中、性能较好
no 命令写入 aof_buf 后执行 write 操作,由 OS 控制频率 不可控

write 和 fsync 是两个系统调用:

  • write 操作会触发延迟写(delayed write)。Linux 在内核提供页缓冲区用来提高磁盘 IO 性能。write 操作在写入系统缓冲区后立即返回。同步磁盘操作依赖系统调度机制,例如:缓冲区页空间写满或者达到特定时间周期。同步文件之前,如果服务挂了,缓冲区数据将丢失
  • fsync 针对单个文件操作,强制同步磁盘,fsync 将阻塞到数据写入完成
  • 配置为 always 时,每次写入都要同步 AOF文件,性能最差,一般不建议配置
  • 配置为 no 时,由于操作系统同步策略不可控,虽然提高了性能,但数据丢失的风险很大,除非数据重要程度很低,不然一般不建议配置
  • 配置为 everysec,为默认配置,也是推荐配置,兼顾了数据安全性和性能

重写机制

随着命令不断写入 AOF,文件会越来越大,会有很多冗余的操作,比如:

set key1 111
set key1 222
set key1 333
set key1 444

对于重启加载数据,其实只要 set key1 444 即可,其他冗余的操作应该去除。
为了解决这个问题,Redis 引入 AOF 重写机制压缩文件体积,通过把 Redis 进程内的数据转化为写命令同步到新的 AOF 文件

例如如下操作,在重写时就可以节省空间:

  • 进程内已超时的数据不再写入文件
  • 旧的 AOF 中无效命令,例如 del、hdel、srem 等重写后将会删除,只需要保留数据的最终版本
  • 多条写操作合并为一条,例如上述操作

重写操作一方面可以降低硬盘空间占用,一方面可以提升启动 Redis 时数据恢复的速度


AOF 重写也可以通过手动触发自动触发两种方式

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

AOF 流程如下:

在这里插入图片描述

  1. 执行 AOF 重写请求。如果当前进程正在执行 AOF 重写,请求不执行;如果当前进程正在 bgsave 操作,重写命令延迟到 bgsave 完成后再执行
  2. 父进程执行 fork 创建子进程,子进程进行重写操作
  3. 父进程 fork 后,继续响应其他命令,所有修改操作写入 AOF 缓冲区 和 AOF 重写缓冲区 ,即 aof_bufaof_rewrite_buf,并根据 appendfsync 策略将 aof_buf 同步到硬盘,保证原始 AOF 文件正确
  4. 子进程有 fork 时的所有内存信息,包括 aof_buf,对 aof_buf 内容进行重写,写到新 AOF 文件
  5. 子进程完成重写后,通过信号通知父进程,父进程把 aof_rewriet_buf 的命令追加到新 AOF 文件
  6. 最后用新 AOF 文件替换旧 AOF 文件

数据恢复

当 Redis 启动时,会根据 RDB 和 AOF 文件的内容,进行数据恢复

在这里插入图片描述

优先使用 AOF 进行数据恢复,关闭 AOF 则使用 RDB


总的来说,Redis 提供两种持久化方案:RDB 和 AOF

RDB 为内存的快照,使用二进制数据,内容更紧凑,占用空间小,恢复速度快。但持久化开销较大,不适合实时持久化,一般用于冷备主从复制

AOF 通过保存修改命令,在恢复时需要重放命令。并且有重写机制来定期压缩 AOF 文件

RDB 和 AOF 都使用 fork 创建子进程,利用 Linux 子进程拥有父进程内存快照的特点进行持久化,尽可能不影响主进程继续处理后续命令

以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到