很多时候我们需要持久化数据也就是将内存中的数据写入到硬盘里面,大部分原因是为了之后重用数据(比如重启机器、机器故障之后恢复数据),或者是为了防止系统故障而将数据备份到一个远程位置。

Redis 不同于 Memcached 的很重要一点就是,Redis 支持持久化,而且支持两种不同的持久化操作。Redis 的一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file, AOF)。这两种方法各有千秋,下面我会详细这两种持久化方法是什么,怎么用,如何选择适合自己的持久化方法。

RDB

RDB持久化的原理

Redis可以通过穿件快找来获得存储在内存里面的数据在某个时间点上的副本.Redis穿件快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而穿件具有相同数据的服务器副本(Redis主从结构,只要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用.

RDB是Redis默认采用的持久化方法.

触发RDB持久化过程分为自动触发和手动出发

自动触发:

  • 使用 save 相关配置,如 save m n,表示 m 秒内数据集存在 n 次修改时,自动触发 bgsave。
1
2
3
4
5
save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
  • 如果从节点执行全量复制操作,主节点自动执行 bgsave 生成 RDB 文件并发送给从节点。
  • 执行 debug reload 命令重新加载 Redis 时也会自动触发 save 操作。
  • 默认情况下执行 shutdown 命令时,如果没有开启 AOF 持久化功能则自动执行 bgsave。

手动触发:

  • save: 阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用。
  • bgsave: Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。bgsave 是针对 save 阻塞问题做的优化,因此 Redis 内部所有涉及 RDB 的操作都采用 bgsave 的方式,而 save 方式已经废弃。

bgsave的原理

  1. 执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。
  2. 父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞。
  3. 父进程 fork 完成后,bgsave 命令返回并不再阻塞父进程,可以继续响应其他命令。
  4. 子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。
  5. 进程发送信号给父进程表示完成,父进程更新统计信息。

RDB的优点

RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适合于备份,全量复制等场景。例如每 6 个消时执行 bgsave 备份,并把 RDB 文件拷贝到远程机器或者文件系统中,用于灾难恢复。

Redis 加载 RDB 恢复数据远远快于 AOF 的方式。

RDB的缺点

RDB 方式数据无法做到实时持久化/秒级持久化,因为 bgsave 每次运行都要执行 fork 操作创建子进程,属于重量级操作,频繁执行成本过高。针对 RDB 不适合实时持久化的问题,Redis 提供了 AOF 持久化方式。

RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个格式的 RDB 版本,存在老版本 Redis 服务无法兼容新版 RDB 格式的问题。

AOF

AOF持久化的原理

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

开启 AOF 功能需要设置:appendonly yes,默认不开启。保存路径同 RDB 方式一致,通过 dir 配置指定。

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

  • 所有的写入命令会追加到 aof_buf 缓冲区中。
  • AOF 缓冲区根据对应的策略向硬盘做同步操作。
  • 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
  • 当服务器重启时,可以加载 AOF 文件进行数据恢复。

在 Redis 的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:

1
2
3
appendfsync always    #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
appendfsync no #让操作系统决定何时进行同步

AOF 命令写入的原理?

AOF 命令写入的内容直接是文本协议格式,采用文本协议格式的原因:

  • 文本协议具有很好的兼容性。
  • 开启 AOF 后所有写入命令都包含追加操作,直接采用协议格式避免了二次处理开销。
  • 文本协议具有可读性,方便直接修改和处理。

AOF 把命令追加到缓冲区的原因:

Redis 使用单线程响应命令,如果每次写 AOF 文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。先写入缓冲区中还有另一个好处,Redis 可以提供多种缓冲区同步硬盘策略,在性能和安全性方面做出平衡。

AOF文件重写的原理

文件重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程,可以降低文件占用空间,更小的文件可以更快地被加载。

重写后 AOF 文件变小的原因:

  • 进程内已经超时的数据不再写入文件。
  • 旧的 AOF 文件含有无效命令,重写使用进程内数据直接生成,这样新的 AOF 文件只保留最终数据写入命令。
  • 多条写命令可以合并为一个,为了防止单条命令过大造成客户端缓冲区溢出,对于 list、set、hash、zset 等类型操作,以 64 个元素为界拆分为多条。

AOF 重写分为手动触发和自动触发,手动触发直接调用 bgrewriteaof 命令,自动触发根据 auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage 参数确定自动触发时机。

重写流程:

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

② 父进程执行 fork 创建子进程,开销等同于 bgsave 过程。

③ 父进程 fork 操作完成后继续响应其他命令,所有修改命令依然写入 AOF 缓冲区并同步到硬盘,保证原有 AOF 机制正确性。

④ 子进程根据内存快照,按命令合并规则写入到新的 AOF 文件。每次批量写入数据量默认为 32 MB,防止单次刷盘数据过多造成阻塞。

⑤ 新 AOF 文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。

⑥ 父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件并替换旧文件,完成重写。

Redis4.0对于持久化的优化

Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 aof-use-rdb-preamble 开启)。

如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分是压缩格式不再是 AOF 格式,可读性较差。

重启加载

AOF 和 RDB 文件都可以用于服务器重启时的数据恢复。Redis 持久化文件的加载流程:

  1. AOF 持久化开启且存在 AOF 文件时,优先加载 AOF 文件。

  2. AOF 关闭时且存在 RDB 文件时,记载 RDB 文件。

  3. 加载 AOF/RDB 文件成功后,Redis 启动成功。

  4. AOF/RDB 文件存在错误导致加载失败时,Redis 启动失败并打印错误信息。

评论




Blog content follows the Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) License

载入天数...载入时分秒... Use Volantis as theme 鲁ICP备20003069号