面试中常常被问到的 Redis 持久化与恢复

本文主要讲了 Redis 的持久化相关功能,持久化一直是影响 Redis 性能的高发地,也是面试中常常被问到的。包括 RDB 相关的特定和优缺点,AOF 的优缺点,事实上,因为 RDB 的数据实时性问题,目前用 AOF 比较多了。而持久化恢复也是优先 AOF。ios

RDB 是旧的模式,如今基本上都使用 AOF。固然,两个都会一块儿说到。面试

RDB

RDB 流程图

RDB 特色

  1. RDB 是一种快照模式,即——保存的是 key value 数据内容。
  2. RDB 有 2 种持久方式,同步 save 模式和异步 bgsave 模式。因为 save 是同步的,因此能够保证数据一致性,而 bgsave 则不能。
  3. save 能够在客户端显式触发,也能够在 shutdown 时自动触发;bgsave 能够在客户端显式触发,也能够经过配置由定时任务触发,也能够在 slave 节点触发。
  4. save 致使 redis 同步阻塞,基本已经废弃。bgsave 则不会致使阻塞,但也有缺点:在 fork 时,须要增长内存服务器开销,由于当内存不够时,将使用虚拟内存,致使阻塞 Redis 运行。因此,须要保证空闲内存足够。
  5. 默认执行 shutdown 时,若是没有开启 AOF,则自动执行 bgsave。
  6. 每次的 RDB 文件都是替换的。

关于优化

Redis 会压缩 RDB 文件,使用 LZF 算法,让最终的 RDB 文件远小于内存大小,默认开启。但会消耗 CPU。redis

RDB 缺点

  1. 没法秒级持久化。
  2. 老版本 Redis 没法兼容新版本 RDB

RDB 优势

  1. 文件紧凑,适合备份,全量复制场景。例如每 6 小时执行 bgsave,保存到文件系统之类的。
  2. Redis 加载 RDB 恢复数据远远快于 AOF。

AOF

因为 RDB 的数据实时性问题,AOF(append only file) 是目前 Redis 持久化的主流方式。算法

AOF 特色

  1. 默认文件名是 appendonly.aof。和 RDB 同样,保存在配置中 dir 目录下。
  2. AOF 相比较于 RDB,每次都会保存命令,数据实时性更高。
  3. AOF 因为每次都会记录写命令,文件会很大,所以须要进行优化,称之为“重写机制”(下面详细说)。
  4. AOF 每次保存的写命令都放在一个缓冲区,根据不一样的策略(下面详细说)同步到磁盘。

“重写机制” 细节

  1. fork 子进程(相似 bgsave)
  2. 主进程会写到2个缓冲区,一个是原有的 “AOF 缓存区”,一个是专门为子进程准备的 “AOF 重写缓冲区”;
  3. 子进程写到到新的 AOF 文件中,批量的,默认 32m;写完后通知主进程。
  4. 主进程把“AOF 重写缓冲区”的数据写到新 AOF 文件中。
  5. 将新的 AOF 文件替换老文件。

重写流程图

缓冲区同步策略,由参数 appendfsync 控制,一共3种:缓存

  1. always:调用系统 fsync 函数,直到同步到硬盘返回; (严重影响redis性能)
  2. everysec:先调用 OS write 函数, 写到缓冲区,而后 redis 每秒执行一次 OS fsync 函数。(推荐使用这种方式) 
  3. no: 只执行 write OS 函数,具体同步硬盘策略由 OS 决定;(不推荐,数据不安全,容易丢失数据) 

持久化恢复

AOF 和 RDB 文件均可以用于服务器重启时的数据恢复,具体流程以下图:安全

从图中能够看出优先加载 AOF,当没有 AOF 时才加载 RDB。当 AOF 或者 RDB 存在错误,则加载失败。性能优化

问题排查和性能优化

Redis 持久化是影响 Redis 性能的高发地,也是面试中常问的问题。服务器

fork 操做

当 Redis 作 RDB 或者 AOF 重写时,必然要进行 fork 操做,对于 OS 来讲,fork 都是一个重量级操做。并且,fork 还会拷贝一些数据,虽然不会拷贝主进程全部的物理空间,但会复制主进程的空间内存页表。对于 10GB 的 Redis 进程,须要复制大约 20MB 的内存页表,所以 fork 操做耗时跟进程总内存量息息相关,再加上,若是使用虚拟化技术,例如 Xen 虚拟机,fork 会更加耗时。架构

一个正常的 fork 耗时大概在 20毫秒左右。为何呢,假设一个 Redis 实例的 OPS 在 5 万以上,若是 fork 操做耗时在秒级,那么僵拖慢几万条命令的执行,对生产环境影响明显。并发

咱们能够在 Info stats 统计中查询 latestforkusec 指标获取最近一次 fork 操做耗时,单位微秒。

如何优化:

一、优先使用物理机或者高效支持 fork 的虚拟化技术,避免使用 Xen。 二、控制 redis 实例最大内存,尽可能控制在 10GB 之内。 三、合理配置 Linux 内存分配策略,避免内存不足致使 fork 失败。 四、下降 fork 的频率,如适度放宽 AOF 自动触发时机,避免没必要要的全量复制。

子进程开销

fork 完毕以后,会建立子进程,子进程负责 RDB 或者 AOF 重写,这部分过程主要涉及到 CPU,内存,硬盘三个地方的优化。

一、CPU 写入文件的过程是 CPU 密集的过程,一般子进程对单核 CPU 利用率接近 90%。 如何优化呢?既然是 CPU 密集型操做,就不要绑定单核 CPU,由于这样会和父 CPU 进行竞争。同时,不要和其余 CPU 密集型服务不是在一个机器上。若是部署了多个 Redis 实例,尽力保证统一时刻只有一个子进程执行重写工做。

二、内存 子进程经过 fork 操做产生,占用内存大小等同于父进程,理论上须要两倍的内存完成持久化操做,但 Linux 有 copy on write 机制,父子进程会共享相同的物理内存页,当父进程处理写操做时,会把要修改的页建立对应的副本,而子进程在 fork 操做过程当中,共享整个父进程内存快照。 即——若是重写过程当中存在内存修改操做,父进程负责建立所修改内存页的副本。这里就是内存消耗的地方。 如何优化呢?尽可能保证同一时刻只有一个子进程在工做;避免大量写入时作重写操做。

三、硬盘 硬盘开销分析:子进程主要职责是将 RDB 或者 AOF 文件写入硬盘进行持久化,势必对硬盘形成压力,可经过工具例如 iostat,iotop 等,分析硬盘负载状况。

如何优化:

不要和其余高硬盘负载的服务放在一台机器上,例如 MQ,存储。

AOF 重写时会消耗大量硬盘 IO,能够开启配置 no-appendfsync-on-rewrite,默认关闭。表示在 AOF 重写期间不作 fsync 操做。

当开启 AOF 的 Redis 在高并发场景下,若是使用普通机械硬盘,每秒的写速率是 100MB左右,这时,Redis 的性能瓶颈在硬盘上,建议使用 SSD。

对于单机配置多个 Redis 实例的状况,能够配置不一样实例分盘存储 AOF 文件,分摊硬盘压力。

 AOF 追加阻塞

当开启 AOF 持久化时,经常使用的同步硬盘的策略是“每秒同步” everysec,用于平衡性能和数据安全性,对于这种方式,redis 使用另外一条线程每秒执行 fsync 同步硬盘,当系统资源繁忙时,将形成 Redis 主线程阻塞。

流程图以下:

经过上图能够发现:everysec 配置最多可能丢失 2 秒数据,不是 1 秒;若是系统 fsync 缓慢,将会致使 Redis 主线程阻塞影响效率。

问题定位:

  1. 发生 AOF 阻塞时,会输入日志。用于记录 AOF fsync 阻塞致使拖慢 Redis 服务的行为。
  2. 每当 AOF 追加阻塞事件发生时,在 info Persistence 统计中,aofdelayedfsync 指标会累加,查看这个指标方便定位 AOF 阻塞问题。
  3. AOF 同步最多运行 2 秒的延迟,当延迟发生时说明硬盘存在性能问题,可经过监控工具 iotop 查看,定位消耗 IO 的进程。

单机多实例部署

Redis 单线程架构没法充分利用多核CPU,一般的作法是一台机器上部署多个实例,当多个实例开启 AOF 后,彼此之间就会产生CPU 和 IO 的竞争。

如何解决这个问题呢?

让全部实例的 AOF 串行执行。

咱们经过 info Persistence 中关于 AOF 的信息写出 Shell 脚本,而后串行执行实例的 AOF 持久化。

整个过程如图:

经过不断判断 AOF 的状态,手动执行 AOF 重写,保证 AOF 不会存在竞争。具体的 Shell 编写以及 info 信息判断,能够查看下图:

总结

本文主要讲了 Redis 的持久化相关功能,持久化一直是影响 Redis 性能的高发地,也是面试中常常被问到的。包括 RDB 相关的特定和优缺点,AOF 的优缺点,事实上,因为 RDB 的数据实时性问题,目前用 AOF 比较多了。而持久化恢复也是优先 AOF。

关于持久化的问题排查,就很麻烦了,但无非几个方面,fork 耗时,子进程的 CPU,内存,硬盘开销,AOF 的同步阻塞,单机多实例部署。这些优化,能够经过前面写的分析进行排查。

最后

后续会持续更新Redis专题知识,你们以为不错能够点个赞在关注下,之后还会分享更多文章!

相关文章
相关标签/搜索