Redis 持久化存储

87 阅读10分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情

Redis 是一个基于内存的数据库,所有数据都是存储在内存中。当 Redis 服务器关机或其他一些异常情况,都会导致存储在内存中的数据丢失。而 Redis 为了解决这种情况的发生,提供了持久化存储的功能

RDB 持久化

RDB 持久化会对 Redis 中的数据进行周期性的持久化,生成一份快照文件,存放在配置文件声明的目录下面的 dump.rdb 文件中。在 Redis 配置文件中可以通过配置 dir 属性来指定持久化文件存放目录。触发 RDB 持久化的过程分为手动触发和自动触发。 接下来我们来学习 RDB 如何进行数据的持久化。

➡️ RDB 持久化原理

  • RDB 持久化的流程

    将 Redis 在内存中的数据定时 dump 到磁盘上,实际操作过程是 fork 一个子进程,先将数据写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。下面是 RDB 简单执行流程图:

    图片描述

➡️ RDB 持久化实现

  • 通过命令触发 RDB(即手动触发)

    a. 通过 save 命令触发(同步、阻塞),也就是说 save 命令执行完毕后才能执行后续的其他命令操作。对于内存比较大的实例会造成长时间的阻塞,线上环境不建议使用。

    127.0.0.1:6379> save
    OK
    127.0.0.1:6379>
    

    b. 通过 bgsave 命令触发(异步、非阻塞),bgsave 命令是 fork 一个专门 save 的子进程,RDB 的持久化过程由子进程负责,完成后自动结束。其中阻塞是发生在 fork 阶段,一般时间很短(微秒级别)。

    127.0.0.1:6379> bgsave
    Background saving started
    127.0.0.1:6379>
    
  • 通过配置文件触发 RDB(即自动触发)

    自动触发,就是通过对 Redis 的配置文件 redis.conf 中相关选项的修改,当达到某个配置好的条件后,自动生成 RDB 文件,其内部使用的是 bgsave 命令。

    a. 可以在 Redis 配置文件 redis.conf 中找到如下内容:

    # save 3600 1
    # save 300 100
    # save 60 10000
    

    ✨ 说明:如果 3600 秒内有 1 个 key 发生了变化,生成一份快照文件;如果在 300 秒内有 100 个 key 发生了改变,生成一份快照文件;如果在 60 秒内有 10000 个 key 发生了改变,生成一份快照文件。这里是 Redis 6.2.6 版本,官方建议配置的最佳参数值,默认这些是注释掉的。

    b. 可以在 Redis 配置文件 redis.conf 中找到 RDB 文件的配置信息,如下所示:

    # 默认文件名(可以自行指定)
    dbfilename dump.rdb
    # 默认文件保存位置(可以自行指定)
    dir ./
    # 假如 bgsave 执行中发生错误,是否停止写入,默认是 yes,表示出错,就停止写入。
    stop-writes-on-bgsave-error yes
    # 是否使用压缩
    rdbcompression yes
    # 是否进行数据的校验
    rdbchecksum yes
    

➡️ RDB 持久化的优缺点

  • 优点

    a. RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照,全量备份,便于数据的传输。

    b. 适合大规模的数据恢复。如果服务器宕机了,不要删除 RDB 文件,重启会自动从指定的目录下读取 RDB 文件,并且数据恢复的速度远大于 AOF 方法。

  • 缺点

    a. 时效性差,容易造成数据的不完整性。由于 RDB 不能实时备份,当某个时间段 Redis 服务出现异常,内存数据丢失,这段时间的数据无法恢复。

    b. RDB 采用加密的二进制格式保存,可能存在新老版本不兼容问题。

AOF 持久化

AOF 持久化会记录服务器执行的所有写操作命令,并在 Redis 重启的时候,通过回访 AOF 文件来还原数据集,文件使用 append-only 的默认,所有操作都会追加到文件的末尾。当 AOF 文件体积超出保存数据集状态的情况下,会进行一个重写(rewrite)操作,确保文件不会太大。通常情况下,AOF 文件保存的数据集会比 RDB 文件保存的数据集更完整。

接下来我们来学习 AOF 如何进行数据的持久化。

➡️ AOF 持久化原理

  • AOF 持久化流程

    将 Redis 的操作日志以文件追加的方式写入文件,只记录写、删除操作,查询操作不会记录(类似于 MySQL 的 Binlog 日志)。下面是 AOF 简单执行流程图:

    图片描述

➡️ AOF 持久化实现

  • 开启 AOF 功能

    默认情况下 AOF 持久化是关闭的,通过以下配置开启 AOF 持久化:

    appendonly yes
    

    ✨ 说明:redis.conf 默认是 appendonly no,表示 AOF 持久化是关闭的。开启后,会在文件存储目录下面生成一个 appendpnly.aof 文件,开启了 AOF 之后,Redis 重启的时候,会优先通过 AOF 进行数据恢复。

  • 设置保护模式(即 AOF 的 fsync 策略)

    打开 AOF 的持久化机制之后,Redis 每接收到一条命令,就会写入日志文件中,然后每隔一定时间再 fsync 一下。可以通过配置以下内容来配置 AOF 的 fsync 策略:

    appendfsync everysec
    

    ✨ 说明:这里 AOF 的 fsync 策略的属性值有 3 个可以配置(下面中的 write 操作是指将数据写到 os cachesave 操作是指将 os cache 中数据写到磁盘):

    • always:每执行一个命令保存一次。这种模式下,每执行一个命令 ,write 和 save 都会被执行,且 save 操作会阻塞主进程。性能会变得比较差,但是可以确保说每一条数据都不会丢失。
    • everysec:每秒钟保存一次。这种模式下,save 原则上每隔一秒钟就会执行一次,具体的执行周期与文件写入、保存时,Redis 所处的状态有关,此模式下 save 操作由后台子线程调用,不会引起服务器主进程的阻塞。这个最常用,生产环境下一般都使用这种策略,性能很高。
    • no:只执行 write 操作,save 操作会被略过,只有在 Redis 被关闭AOF 功能被关闭系统的写缓存被刷新(如缓存已被写满)这三种情况,save 操作才会被执行,但是这三种情况都会引起 Redis 主进程阻塞。这种策略,会让我们的数据不可控,因为无法预知操作系统什么时候会把数据刷到磁盘。
  • 关于 AOF 持久化在 redis.conf 配置文件中可以找到以下相关内容,进行配置:

    # 此选项为 AOF 功能的开关,默认为“no”,通过“yes”来开启 AOF 功能
    appendonly yes
    # 指定 AOF 文件名称(可以自定义)
    appendfilename appendonly.aof
    # 备份文件存放路径(此参数同样适用于指定RDB备份文件存放路径)
    dir ./
    # 三种备份策略(三者只需要开启以一个即可)
    appendfsync everysec
    

➡️ AOF 文件重写(rewrite)

  • AOF 文件重写的原因

    Redis 中的数据是有限的,很多数据可能会自动过期,也有可能会被用户删除,但是这些操作都会被 AOF 文件记录下来,所以有可能存在 AOF 文件越来越大的情况,意思就是说,重建数据集根本不需要执行所有 AOF 记录的命令,为了处理这种情况,Redis 提供了一种 rewrite 策略。

  • 重写的基本流程

    图片描述

    a. Redis 会 fork 一个子进程。

    b. 子进程基于当前内存中的数据,构建日志,开始往一个新的临时 AOF 文件中写入日志。

    c. Redis 主进程,接收到 client 的写操作,在内存中写入日志,同时新的日志也继续写入旧的 AOF 文件。

    d. 子进程完成新的日志文件之后,Redis 主进程将内存中的新日志再次追加到新的 AOF 文件中。

    e. 用新的日志文件替换旧的日志文件。

  • 重写 AOF 文件的两种方式

    a. 手动重写:在 Redis 2.4 之前是需要手动执行 bgrewriteaof 命令来进行重写 AOF 文件。

    b. Redis 2.4 版本之后提供了自动 rewrite 的操作。我们可以配置 rewrite 的策略。

    # AOF 文件容量的增长率
    auto-aof-rewrite-percentage 100
    # AOF 文件的最低容量,就是当前文件的大小大于此值时,就会进行重写。当然这只是其中一个条件。
    auto-aof-rewrite-min-size 64mb
    

    ✨ 说明:这两个参数的意思是,最少 AOF 文件需要达到 64mb 才会进行重写,重写了之后,当检测到当前的 AOF 文件增长幅度大于 100%,也就是 64mb,即当前的 AOF 文件大小为 128mb 的时候,就会自动触发对 AOF 进行重写操作。

  • AOF 破损文件的修复

    如果 AOF 文件破损了,可以使用 redis-check-aof --fix filename 命令来修复破损的 AOF 文件,比如下面示例:

    redis-check-aof --fix appendonly.aof
    

➡️ AOF 持久化的优缺点

  • 优点

    a. 拥有更高的数据可用性,数据持久化最完整。

    b. 日志文件采用 append-only 模式,没有任何磁盘寻址的开销,性能非常高,即使文件损坏了,也可以通过 Redis 提供的工具进行修复。

    c. 提供 rewrite 机制,当日志过大时,Redis 以 append-only 模式不断将修改的日志写入老的磁盘文件,同时 Redis 还会创建一个新的文件用于记录此期间有哪些命令被执行。

  • 缺点

    a. 同一份数据,通常 AOF 会比 RDB 文件更大,AOF 开启后,支持的写 QPS 会比 RDB 的低,因为 AOF 一般设置为每秒 fsync 一次日志文件,其次在数据恢复的时候,会比较慢,做冷备不太适合。

RDB 和 AOF 的对比

➡️ AOF 和 RDB 的区别

命令AOFRDB
启动优先级
体积
恢复速度
数据安全性由策略决定丢数据
轻重

➡️ 持久化方式的选择

  • 如何选择持久化方式

    a. 不要仅仅使用 RDB 方式,因为那样有可能会导致丢失较多数据。

    b. 不要仅仅使用 AOF 方式,因为使用 AOF 进行数据恢复速度较慢,而且使用 RDB 生成快照的方式更加健壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug。

    c. 综合使用 AOF 和 RDB 两种持久化机制,用 AOF 保证数据不丢失,作为数据恢复的第一选择;用 RDB 来做不同程度的冷备,在 AOF 文件丢失或者不可用的情况下,可以使用 RDB 来进行数据恢复。

➡️ 两种持久化方式的数据恢复方案

  • 数据恢复方案

    a. 如果是 Redis 进程挂掉,那么重启 Redis 进程即可,直接基于 AOF 日志文件恢复数据。x

    b. 如果是 Redis 进程所在机器挂掉,那么重启机器后,尝试重启 Redis 进程,尝试直接基于 AOF 日志文件进行数据恢复,如果 AOF 文件破损,那么用 redis-check-aof fix filename 命令修复。

    c. 如果 Redis 当前最新的 AOF 和 RDB 文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的 RDB 数据副本进行数据恢复。

    d. 在数据完全丢失的情况下,基于 RDB 冷备,可以采用下面恢复数据方案:

    • 停止 Redis
    • 关闭 AOF
    • 拷贝 RDB 备份文件
    • 重启 Redis
    • 确认数据恢复
    • 在 redis-cli 开启 AOF(redis config set)
    • 此时 AOF 和 RDB 两份数据文件数据同步
    • 停止 Redis
    • 修改配置文件,开启 AOF
    • 重启 Redis

    e. 如果当前机器上的所有 RDB 文件全部损坏,那么从远程的云服务上拉取最新的 RDB 快照回来恢复数据。

    f. 如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了,那么可以选择某个更早的时间点,对数据进行恢复。