2 Redis 持久化

2.1 持久化简介

2.1.1 什么是持久化?

持久化简介.png

  • 利用永久性的存储介质(如:硬盘等)将数据进行保存,在特定的时间,将保存的数据进行恢复的工作机制称为持久化。

    2.1.2 为什么要进行持久化?

  • 防止数据的意外丢失,确保数据安全。

    2.1.3 持久化过程中保存什么?

  • 将当前数据状态进行保存(类似于快照形式),存储数据结果,存储格式简单,关注点在于数据。

  • 将数据的操作过程进行保存(类似于日志形式),存储操作过程,存储格式复杂,关注点在于数据操作。

持久化过程中保存什么.png

2.2 RDB

2.2.1 RDB 启动方式 — save 指令

  • 命令:

    1. save
  • 作用:手动执行一次保存操作。

  • 示例:

    1. keys *
    1. set name 123
    1. save

    save 指令示例.gif

    2.2.2 RDB 启动方式 — save 指令相关配置

  • 技巧:将 redis.conf 文件的注释和空格去掉

    1. cat /opt/redis-5.0.10/redis.conf | grep -v "#" | grep -v "^$" > redis.conf.bak

    将 redis.conf 文件的注释和空格去掉.gif

  • save 指令相关配置:

  • dbfilename dump.rdb
    • 说明:设置本地数据库文件名,默认值为 dump.rdb
    • 经验:通常设置为 dump-端口号.rdb
  • dir ./
    • 说明:设置存储 .rdb 文件的路径。
    • 经验:通常设置成存储空间较大的目录中,目录名称 data
  • rdbcompression yes
    • 说明:设置存储到本地数据库是否压缩数据,默认为 yes ,采用 LZF 压缩。
    • 经验:通常默认为开启状态,如果设置为 no ,可以节省 CPU 运行时间,但是会使得压缩文件变得很大。
  • rdbchecksum yes
    • 说明:设置是否进行 RDB 文件格式校验,该校验过程在写文件和读文件过程均进行。
    • 经验:通常默认为开启状态,如果设置为 no ,可以节约读写性过程约 10% 时间消耗,但是存在一定的数据损坏风险。

      2.2.3 RDB 启动方式 — save 指令工作原理

      RDB 启动方式 -- save 指令工作原理.gif

注意:save 指令的执行会阻塞当前 Redis 服务器,直到当前 RDB 过程完成为止,有可能会造成长时间阻塞,线上环境不建议使用

2.2.4 RDB 启动方式 — bgsave 指令

  • 问:数据量过大,单线程执行方式造成效率过低如何处理?
  • 答:后台执行。
  • 命令:

    1. bgsave
  • 作用:手动启动后台保存操作,但是不是立即执行。

RDB 启动方式 -- bgsave 指令示例.gif

2.2.5 RDB 启动方式 — bgsave 指令工作原理

RDB 启动方式 -- bgsave 指令工作原理.png

注意:bgsave 指令是针对 save 阻塞问题做的优化。Redis 内部所有涉及到 RDB 操作都可以采用 bgsave 指令的方式,save 指令可以放弃使用

2.2.6 RDB 启动方式 — bgsave 指令相关配置

  • dbfilename dump.rdb :略(和 save 指令相关配置相同)。
  • dir ./ :略。
  • rdbcompression yes :略。
  • rdbchecksum yes :略。
  • stop-writes-on-bgsave-error yes

    • 说明:后台存储过程中如果出现错误现象,是否停止保存操作。
    • 经验:通常默认为开启状态。

      2.2.7 RDB 启动方式 — save 配置

  • 问:反复执行保存指令,忘记了怎么办?不知道数据产生了多少变化,何时保存?

  • 答:自动执行。
  • 配置(redis.conf):

    1. save second changes
  • 作用:满足限定时间内 key 的变化数量达到指定数量就进行持久化操作。

  • 参数:
    • second :监控时间范围。
    • changes:监控 key 的变化量。
  • 示例:
    1. save 900 1
    2. save 300 10
    3. save 60 10000

    2.2.8 RDB 启动方式 — save 配置工作原理

    RDB 启动方式 -- save 配置工作原理.png

    注意:

    • save 配置要根据实际业务情况设置,频度过高或过低都会出现性能问题,结果可能是灾难性的。
    • save 配置中对于 second 和 changes 设置通常具有互补对应关系,尽量不要设置成包含关系。
    • save 配置启动后执行的是 bgsave 操作。

2.2.9 总结

  • RDB 三种启动方式对比: | 方式 | save 指令 | bgsave 指令 | save 配置 | | —- | —- | —- | —- | | 读写 | 同步 | 异步 | 异步 | | 阻塞客户端指令 | 是 | 否 | 否 | | 额外内存消耗 | 否 | 是 | 是 | | 启动新进程 | 否 | 是 | 是 |

  • RDB 特殊启动形式:

    • ① 主从复制:在主从复制中详细讲解。
    • ② 服务器运行过程中重启。

      1. debug reload
    • ③ 关闭服务器时指定保存数据:

      1. shutdown save
  • RDB 优点:

    • ① RDB 是一个紧凑压缩的二进制文件,存储效率高。
    • ② RDB 内存存储的是 Redis 在某个 时间点 的数据快照,非常适合用于数据备份,全量复制等场景。
    • ③ RDB 恢复数据的速度要比 AOF 快很多。
    • ④ 应用:服务器中每 x 小时执行 bgsave 备份,并将 RDB 文件拷贝到远程机器中,用于灾难恢复。
  • RDB 缺点:

    • ① RDB 方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据。
    • ② bgsave 指令每次运行要执行 fork 操作创建子进程,要牺牲掉一些性能。
    • ③ Redis 的众多版本中未进行 RDB 文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象。

      2.3 AOF

      2.3.1 RDB 存储的弊端

  • ① 存储数据量较大,效率较低:基于快照思想,每次读写都是全部数据,当数据量巨大的时候,效率非常低。

  • ② 大数据量下的 IO 性能较低。
  • ③ 基于 fork 创建子进程,内存产生额外消耗。
  • ④ 如果不是实时做快照,那么宕机会带来数据丢失的风险。

    2.3.2 解决思路

  • ① 不写全数据,仅记录部分数据。

  • ② 改记录数据为记录操作过程。
  • ③ 对所有操作均进行记录,排除丢失数据的风险。

    2.3.3 AOF 简介

  • AOF(Append Only File)持久化:以独立日志的方式记录每次命令,重启时再重新执行 AOF 文件中命令达到恢复数据的目的,和 RDB 相比可以描述为 改记录数据为记录数据产生的过程

  • AOF 的主要作用是解决了数据持久化的实时性,目前已经是 Redis 持久化的主流方式。

    2.3.4 AOF 写数据过程

    AOF 写数据过程.gif

    2.3.5 AOF 写数据的三种策略(appendfsync)

  • ① always(每次):每次写入操作均同步到 AOF 文件中,数据零误差,性能较低(大数据量下时,系统的资源被 IO 大量占用,那么业务系统的性能将会有所影响),不建议使用。

  • ② everysec(每秒):
    • 每秒将缓冲区中的指令同步到 AOF 文件中,数据准确性较高,性能较高
    • 在系统突然宕机的情况下丢失 1 秒内的数据。
    • 建议使用,也是默认配置。
  • ③ no(系统控制):由操作系统控制每次同步到 AOF 文件的周期,整体过程不可控 ,不建议使用。

    2.3.6 AOF 功能开启

  • appendonly yes|no:是否开启 AOF 持久化功能,默认为不开启状态。

  • appendfsync always|everysec|no:AOF 写数据策略,默认为 everysec 。
  • dir ./ :AOF 持久化文件保存路径,与 RDB 持久化文件保持一致即可。
  • appendfilename "appendonly.aof" :AOF 持久化文件名,默认文件名为 appendonly.aof ,建议配置为 appendonly-端口号.aof 。

    2.3.7 AOF 重写

  • 如果连续执行如下指令该如何处理?

AOF 重写问题.png

  • AOF 重写:随着命令不断写入 AOF,文件会变得越来越大,为了解决这个问题,Redis 引入了 AOF 重写机制来压缩文件体积。AOF 文件重写是将 Redis 进程内的数据转换为写命令同步到新 AOF 文件的过程。简单来说,就是将对统一数据的若干条命令结果转换成最终结果数据对应的指令进行记录。
  • AOF 重写的作用:
    • ① 降低磁盘占用量,提高磁盘利用率。
    • ② 提高持久化效率,降低持久化写时间,提高 IO 性能。
    • ③ 降低数据恢复用时,提高数据恢复效率。
  • AOF 重写的规则:
    • ① 进程内已超时的数据不再写入文件。
    • ② 忽略无效指令,重写时使用进程内的数据直接生成,这样新的 AOF 文件只保存最终数据的写入命令。
      • 如:del key1、hdel key2、srem key4、set key4 111、set key4 222等。
    • ③ 对同一数据的多条命令合并为一条命令。
      • 如:lpush list1 a、lpush list1 b、lpush list1 c 可以转为为 lpush list1 a b c。
      • 为了防止数据量过大造成客户端缓冲区溢出,对 list、set、hash、zset 等类型,每条指令最多写入 64 个元素。

2.3.8 AOF 重写方式

  • 手动重写:
    1. bgrewriteaof

AOF 手动重写工作原理.png

  • 自动重写:
  1. auto-aof-rewrite-min-size size
  1. auto-aof-rewrite-percentage percentage
  • 自动重写触发比对参数(运行指令 info persistence 获取具体信息):
  1. aof_current_size
  1. aof_base_size
  • 自动触发条件:

持久化 - 图12

持久化 - 图13

2.3.9 AOF 工作流程

AOF 工作流程.png

2.3.10 AOF 重写流程

AOF 重写流程1.png
AOF 重写流程2.png

2.4 RDB 和 AOF 的区别

2.4.1 RDB VS AOF

持久化方式 RDB AOF
占用存储空间 小(数据级:压缩) 大(指令级:重写)
存储速度
恢复速度
数据安全性 会丢失数据 依据策略决定
资源消耗 高/重量级 低/轻量级
启动优先级

2.4.2 RDB 和 AOF 选择之惑

  • 对数据非常敏感,建议使用默认的 AOF 持久化方案。
    • AOF 持久化策略使用 everysec,每秒钟 fsync 一次。该策略 Redis 依然可以保持很好的处理性能,当出现问题的时候,最多丢失 0 ~ 1 秒内的数据。
    • 注意:由于 AOF 文件存储体积较大,且恢复速度较慢。
  • 数据呈现阶段有效性,建议使用 RDB 持久化方案。
    • 数据可以良好的做到阶段内无丢失(该阶段是开发人员或运维人员手动维护的),且恢复速度较快,阶段性数据恢复通常采用 RDB 方案。
    • 注意:利用 RDB 实现紧凑的数据持久化会使 Redis 性能下降的非常厉害(Redis 中的数据越多,频繁的进行 RDB 持久化,将会使得性能下降的比较厉害)。
  • 总结:

    • RDB 和 AOF 的选择实际上是做一种权衡,各有利弊。
    • 如果不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用 AOF 。
    • 如果能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用 RDB 。
    • 灾难恢复选用 RDB 。
    • 双保险策略,同时开启 RDB 和 AOF ,重启后,Redis 优先使用 AOF 来恢复数据,降低数据丢失的量。

      2.5 持久化的应用场景

  • Redis 用于控制数据库表主键 id,为数据库表主键提供生成策略,保障数据库表的主键唯一性(不建议持久化,临时存储即可,因为如果 Redis 中的数据保存的主键 id 是 18,但是持久化到文件中却是 17 ,那么 Redis 宕机重启后,会恢复为 17 ,这样数据库表中就会造成主键重复的现象)。

  • Redis 应用于各种结构型和非结构型高热度数据访问加速(不建议持久化)。
  • Redis 应用于购物车数据存储设计(不建议持久化)。
  • ④ Redis 应用于抢购、限购类、限量发放优惠券、激活码等业务的数据存储设计。
  • ⑤ Redis 应用于具有操作先后顺序的数据控制。
  • ⑥ Redis 应用于最新消息展示。
  • Redis 应用于同类信息的关联搜索、二度关联搜索、深度关联搜索
  • ⑧ Redis 应用于基于黑白名单设定的服务控制。
  • ⑨ Redis 应用于计数器组合排序功能对应的排名。
  • Redis 应用于即时任务/消息队列执行管理(不建议,可以使用直接 MQ )。
  • Redis 应用于按次结算的服务控制