Redis 持久化机制——RDB 和 AOF 机制

概览

本文主要介绍 Redis 的持久化机制,包含为什么需要持久化,持久化的二种方式,如何配置持久化,持久化的最佳实践。

为什么需要持久化

我们知道 Redis 的数据是保存在内存中的,如果突然宕机或者 Redis 进程突然挂掉的话,内存中的数据就会全部丢失。如果没有机制来保证 Redis 的数据不会因为故障而丢失的话,那么这个时候如果有大量的请求的进来的话,可能就会造成缓存雪崩。所以需要一种机制来保证在出现故障时,可以使 Redis 中的数据恢复,这种机制就是 Redis 持久化机制。即把 Redis 保存在内存中的数据持久化到磁盘中,并且同步到云存储设备上。当出来故障时,从磁盘中恢复数据。

持久化的二种方式

Redis 的持久化机制有二种,一种是 RDB 机制,另一是 AOF 机制。Redis 默认开启了 RDB 机制。AOF 机制需要手动开启。当然如果我们只是把 Redis 当作纯内存的缓存来使用的话,也可以关闭 Redis 的 持久化机制。

RDB 机制

RDB 机制也叫做快照机制,是对 Redis 中的数据的一次全量备份,是内存数据的二进制序列化形式,在存储上非常紧凑,其代表了 Redis 某一时刻的全部数据,这种数据非常适合进做冷备,可以将这种数据保存到一些案例的云存储设备,通过合适的备份策略进行定期的备份 Redis 中的数据,

RDB 机制原理

Redis 是单线程程序,这个线程需要负责多个客户端套接字的并发读写操作和内存数据结构的逻辑读写。在服务请求的时候,Redis 还需要进行内存持久化,其要求 Redis 必须进行文件 IO 操作,而文件 IO 操作是不能使用多路复用 API 的。并且文件 IO 操作会严重的拖累服务器的性能。

同时,为了不阻塞线上的业务,Redis 就需要一边进行持久化,一边响应客户的请求。持久化的同时,内存中的数据结构还在变化,比如一个大型的数据字典还是持久化,结束来了一个请求把它给删除掉了,可它还没有持久化结束,又该如何处理呢?

上面的这几个问题 Redis 是如何解决呢?Redis 使用了操作系统的多进程 COW (Copy On Write) 机制来实现 RDB 持久化。那具体是如何操作的呢?

Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进行继续处理客户端的请求。子进程刚产生的时候,它和父进程共享内存里面的代码段和数据段。这是 Linux 操作系统的机制,为了节省内存资源,所以尽可能的让它们共享资源。在进程分离的一瞬间,内存的增长几乎没有明显变化。

子进程做数据持久化,不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘里去。但是父进程不一样,会不断接收客户端的请求,然后对内存中的数据结构进行不断的修改。此时,会使用操作系统的 COW 机制进行数据段页面的分离。当父进程修改数据时,会将共享的数据页面复制一份分离出来,然后对复制的页面进行修改,这时候子进程相应的页面是没有发生变化的,还是进程那一瞬间的数据。

由于子进程中的数据没有发生过变化,它能够获得的的内存数据在子进程产生的一瞬间就固定了,不会发生改变,这也是把 RDB 机制也叫做快照机制的原因。

如何配置 RDB 持久化

默认 RDB 持久化是打开的,其配置是:

# 表示每隔 900s, 如果有一个 key 发生变化就生成一个 rdb 文件。 
save 900 1
# 表示每隔 300s, 如果有10个 key 发生变化时就生成一个 rdb 文件。
save 300 10
# 表示每隔 60s ,如果有10000个 key 发生变化时就生成一个 rdb 文件。
save 60 10000

save 可以配置多个,也就是配置多个检查点,每到一个检查点的时间,就会去检查一次,是否有指定数据量的 key 发生了变更,如果有就生成一个新的 rdb 文件,然后用新的 rdb 文件覆盖旧的 rdb 文件。

如果你的数据变更频繁的话,可以把指定数量的值设置大一点,比如 10000。而如果数据变更很少时,可以把指定数据的值设置小一点,比如 100 ,这可以根据业务进行相应的调整。

RDB 持久化操作除了 Redis 自动去检查进行持久化,还可以手动调用 savebgsave 命令,同步或者异步进行持久化。

需要注意的是:在执行 redis-cli shutdownflushdbflushall 也会进行 rdb 持久化操作

RDB 机制流程

  1. Redis 根据配置判断是否需要生成 RDB 快照文件。
  2. 父进程 fork 出一个子进程。
  3. 子进程对内存中的数据 dump 到临时 rdb 快照文件中。
  4. 用新生成的 rdb 文件替代磁盘中旧的 rdb 快照文件。

AOF 机制

相比 rdb 快照持久化机制的全量备份,AOF 持久化机制是连续的增量备份。记录的是内存数据修改的指令记录文本。AOF 日志在长期的运行过程中变得无比庞大,Redis 重启后需要加载 AOF 日志进行指令重放,这个时间就会无比漫长,所以需要进行定期进行 AOF 重写,给 AOF 日志进行瘦身。

AOF 原理

AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。由于 AOF 日志记录了 Redis 实例修改性指令序列,那就可以对一个空的 Redis 实例顺序执行所有的指令 – 也就是“重放”,来恢复 Redis 当前实例的内存数据结构的状态。

Redis 收到修改请求时,会进行参数校验、逻辑处理,如果没有问题,就会立即将该指令文本存储到 AOF 日志中,也就是先执行指令才将日志存盘。虽然说是存储磁盘,但是也先写入操作系统的 OSCahce,然后再写磁盘。

Redis 在长期运行运程的过程中,AOF 日志会越来越长。如果实例重启,那么重放整个 AOF 日志会非常耗时,导致 Redis 长时间无法对外提供服务,所以需要对 AOF 日志瘦身。

AOF 重写 rewrite

Redis 中的数据是有限的,很多数据会自动过期,也可能被用户手动删除。Redis 会通过缓存清除算法不断淘汰旧的,就一部分常用的数据自动保留在 redis 内存中。所以很多清除的数据对应的指令数据还存储在 AOF 日志中,而 AOF 日志只有一个,如果不对其进行瘦身,会不断膨胀,到很大很大。

Redis 提供了 bgrewriteaof 指令用于对 AOF 日志进行瘦身,其原理就是开辟一个子进程以内存进行遍历,转换成一系列 Redis 的操作指令,序列化成一个新的 AOF 日志文件中。序列化完毕后再将操作期间发生的增量 AOF 日志追加到这个新的 AOF 日志文件中,追加完毕后就立即替代旧的 AOF 日志了,瘦身工作就完成了。就比如:AOF 日志中有 100 万数据,但是内存中只有 10万数据,就会对内存中这 10 万数据进行重新生成一份新的数据文件,然后覆盖旧的 AOF 日志。

如何配置 AOF 持久化机制

默认情况下,AOF 持久化机制是关闭的。通过修改 appendonly yes 打开 AOF 持久化。在生产环境一般是打开 AOF 机制的,除非说随便丢失几分钟数据也无所谓。

AOF 日志是以文件的形式存在的,程序对 AOF 日志文件进行写操作时,实际上是将内容写到内核缓存(OSCache)中,然后内核会异步将脏数据刷回到磁盘中。

这就意味着如果机器突然宕机,AOF 日志内容可能还没有来得及完全刷到磁盘中,这个时候就会出现日志丢失。

Linux 的 glibc 提供了 fsync 函数可以将指定文件的内容强制从内存缓存中刷到磁盘。只要 Redis 进程实时调用 fsync 函数就可以保证 AOF 日志不丢失。但是 fsync 是一个磁盘 IO 操作,这个操作很慢。如果这样的话就无法保证高性能。

所以在生产环境中,Redis 通常是每隔 1s 左右执行一次fsync 操作,这个 1s 的周期是可以配置的。这是在数据安全性和性能之间做的一个折中,在保持高性能的同时,尽可能使数据丢失。

同时,Redis 提供了另外两种策略,一个是永不调用 fsync——让操作系统决定何时刷新到磁盘,这样做很不安全。另外一个就是来一个指令就调用 fsync 一次,其导致非常慢。这两种策略在生产环境中基本不会使用。

这三种策略的具体配置如下:

  • appendfsync always: 每执行一次指令,就写入磁盘。可以保证数据不丢失,但性能慢。
  • appendfsync everysec: 每秒刷新一次磁盘,兼容安全性和性能。生产基本使用这种策略。
  • appendfsync no: 不主动执行数据同步策略,由操作系统决定何时写入磁盘。

企业级的数据持久化和恢复策略

备份策略

在生产中,一般都会同时开启 RDB 和 AOF 持久化机制。RDB 机制一般使用默认的机制即可以。AOF 机制一般使用 appendfsync everysec配置,即每秒进行一次同步。

对于 AOF 需要配置何时生成一个新的 AOF 文件。

#就是当前AOF大小膨胀到超过上次100%,即上次的两倍时就生成新的 AOF 文件。
auto-aof-rewrite-percentage 100 
#根据你的数据量来定,16mb,32mb,即数据达到指定的数量时就生成新的 AOF 文件。
auto-aof-rewrite-min-size 64mb  

使用 RDB 做冷备,每次生成后就不会发生改变。一般的备份策略可以是以下方案:

  • 通过定时任务进行数据备份。
  • 每小时做一次 rdb 数据备份,保留48小时的数据即可。
  • 每天做一次 rdb 数据备份,保留一个月的数据即可。
  • 每次备份时,把最旧的数据删除掉。
  • 每天晚上把当天的所有备份数据上传到云存储上面去。

有人可能会有疑问,既然做了每小时的备份,为什么还需要做每天的一次备份,这是为了防止最近二天的数据都是脏数据的情况下,使用之前的数据进行恢复。

恢复策略

  1. 如果是 redis 进程挂掉的话,直接重启 redis 服务即可。

  2. 如果是 redis 的服务器挂掉的话,尝试重启 redis ,尝试直接基于 AOF 日志文件进行数据恢复,如果 AOF 文件未损害,可以直接基于 aof append-only 顺序写入。如果文件损坏的,可以使用 redis-check-aof fix 进行恢复。

  3. 如果当前服务器的 RDB 和 AOF 文件丢失或损坏的话,可以尝试基于该机器的某个最新的 RDB 数据备份进行数据恢复。

    具体操作可参考如下:

    • 修改配置文件,关闭 AOF 持久化机制。因为此时如果 AOF 机制开启,redis 会优先基于 AOF 文件把数据写入内存中,如果此时磁盘中的 AOF 文件丢失的话,则生成一个新的 AOF 文件,此时这个文件中不会有指令数据。那么重启后,redis 中不会有数据。
    • 拷贝一份最新的 rdb 备份数据到 redis 的数据目录上。
    • 启动 redis。
    • 通过 redis-cli,利用命令的方式 打开 AOF 持久化机制,即执行 CONFIG SET appendonly yes 命令。
    • 观察数据恢复完成。
    • 关闭 redis。
    • 修改 redis 配置文件,打开 AOF 持久化机制。
    • 重启 redis。

总结

  1. Redis 有二种持久化机制,分别是 RDB 持久化机制和 AOF 持久化机制。
  2. RDB 机制是对数据的全量备份,AOF 是对数据的增量备份。
  3. RDB 机制是默认打开的,而 AOF 机制默认是关闭的。
  4. RDB 机制由于是全量的备份,适合用来做冷备。
  5. 在生产环境下,一般会同时使用 RDB 机制和 AOF 机制。

   转载规则


《Redis 持久化机制——RDB 和 AOF 机制》 孤独如梦 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
【Elasticsearch 系列】 Elasticsearch 7.2.0 集群部署 【Elasticsearch 系列】 Elasticsearch 7.2.0 集群部署
准备这里用三台服务器作为演示部署 ES 集群,三台服务器的 IP 映射关系为: 192.168.56.101 worker-01 worker-01.joyxj.com 192.168.56.102 worker-02
2019-07-15
下一篇 
redis 快速安装及配置开机自启动 redis 快速安装及配置开机自启动
前言本文介绍单机 redis 的安装及配置开机自启动,操作系统为 Centos 7。 下载和解压缩下载最新的稳定版 ridis (5.0.5) , 下载地址:http://download.redis.io/releases/redis-5
2019-07-11
  目录