Redis 之持久化

目录

一.前言

二.持久化类型之 RDB

三.持节化类型之AOF

四.Redis 持久化类型的抉择

五.持久化的恢复

六.持久化问题的分析定位与优化

七.回顾总结


一.前言

首先,来回顾下前面文章的知识.Redis的特性之一就是读取速度快,因为它的数据是存储在内存中的,但是这样还有它的不足之处,那就是当你服务器断电时或者进程产生进退后,那么你所存储在内存中的数据也就荡然无存了,可是这样会给我们带来丢失数据的危险.而Redis正是考虑到了这一点,所以便有了持久化的功能.而持久化的作用正像它的名称一样,便是为了保持数据的持久.

Redis的持久化类型有两种,一种是全量(RDB),一种是增量(AOF),今天这篇文章中便来聊聊这两种类型的特性和他们的优缺点,以及我们在这两种类型中如何做选择.

 

二.持久化类型之 RDB

 

1.什么事RDB?

RDB是把Redis中的完整的数据生成一个快照,然后保存到硬盘当中,那么这就是一个RDB文件了,不过这个RDB文件是一个二进制的文件.当你的Redis服务重启时,它会去载入这样的RDB文件.其作用便是为了备份数据和恢复数据,当然它也是一个复制的媒介,对于Redis的主从复制正式利用这个文件来完成的.

2.触发机制

RDB的触发方式有两种,分别是:save(同步)和bgsave(异步).因为save的触发方式是同步的,那么它会阻塞当前的Redis服务器,直到RDB的过程完成为止,如果你的内存比较大的话,那么会造成长时间的阻塞,所以这在生产环境是不建议使用的.而bgsave是异步的,使用它时Redis的进程会执行fork操作来创建子进程,在RDB持久化的过程便交给子进程去负责了,完成后就回自动结束.对bgsave而言,它的阻塞只会发生在fork阶段,时间一般较短,但也有极少的情况下,会阻塞进程.

我们还需要注意以下几点:

1.save 可以在客户端显式触发,也可以在 shutdown 时自动触发;bgsave 可以在客户端显式触发,也可以通过配置由定时任务触发,也可以在 slave 节点触发.

2.默认执行 shutdown 时,如果没有开启 AOF,则自动执行 bgsave

3.因为RDB是全量的,所以每次使用RDB的时候 RDB 文件都是替换的.

3.RDB的优缺点

优点:

  1. RDB是紧凑压缩的二进制文件,是Redis某个时间点上的数据快照,比较适合用于备份和全量复制,例如每 6 小时执行 bgsave,保存到文件系统之类的.
  2. Redis 加载 RDB 恢复数据远远快于 AOF.

缺点:

  1. 无法实现到实时持久化/秒级持久化.因为bgsave每次都要执行fork操作子进程,这是重量级操作,执行成本过高.
  2. 老版本 Redis 无法兼容新版本 RDB文件.

RDB流程图:

 

 

三.持节化类型之AOF

1.什么事AOF?

AOF是一独立日志方式记录每次命令,其主要作用也是为了解决数据持久化的实时性,目前是Redis持久化的主流方式.

2.AOF的特性

  1. 使用AOF是需要设置配置:appendonly yes,默认是不开启的.AOF文件名是通过appendfilename配置的,默认文件名是:appendonly.aof. 保存的路径和RDB方式一致,通过dir配置指定.
  2. AOF每次都是append卸乳命令,因此实时性更高.
  3. AOF其实并不是直接把数据写入磁盘文件中,而是写在缓冲区(aof_bug)中,这也是为了提高写入效率,它可以根据不同的策略(always,everysec,no)向磁盘中做同步操作.
  4. 随着AOF写入的文件越来越大(因为AOF是增量的),所以需要定期对AOF进行重写,需要进行优化,称之为“重写机制”,以达到压缩的目的.

3.AOF缓冲区同步策略

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

1.alwayss:调用sync函数,操作同步到AOF文件,直到写入硬盘后返回,这将严重影响redis性能.(配置always时,每次都需要同步AOF文件,一般的SATA硬盘,Redis只有大约几百的TPS,显然是与Redis高性能背道而驰的,所以不建议配置)

2.everysec:调用系统write 函数,写入到缓存区后,直接返回.而fsync同步文件操作有专门的线程,每秒调用一次,推荐配置.(理论上系统宕机也就是丢失下一秒的数据)

3.no: 只执行 write OS 函数,不对AOF文件做fsync操作同步,具体同步硬盘策略由 OS 决定,通常周期最长为30秒,不推荐,数据不安全,容易丢失数据.

4.AOF重写机制

  1. 执行AOF重写请求,父进程fork子进程,开销等同于bgsave.
  2. 主进程会写到2个缓冲区,一个是原有的 “AOF 缓存区”,一个是专门为子进程准备的 “AOF 重写缓冲区”,用来保存部分新数据,防止新的AOF文件生成期间丢失这部分数据.
  3. 子进程根据内唇快照,按照命令合并规则写入到新的AOF文件,每次写入是批量的(写入的数据量可配置aof-rewrite-incremental-fsync),默认是30MB,防止单次刷入的数据量过多,造成阻塞.新的AOF文件写入完成后,子进程会通知父进程.
  4. 父进程吧AOF重写缓存区的数据写入新的AOF文件.
  5. 然后使用新的AOF替换老文件,至此完成重写.

重写流程图:

 

四.Redis 持久化类型的抉择

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

 

RDB的最佳策略:

  1. 建议“关”掉RDB(这里的关用引号,是因为对于Redis的主从复制的全量复制是要我们的主节点执行一次bgsave,然后吧RDB文件传给从节点来实现一个复制的过程.)
  2. 集中管理(虽然RDB是一个很重的操作,但是对于数据备份是有一定作用的,如果按天/小时这样一个比较大的量级来备份数据,这样RDB是一个不错的选择,因为RDB文件比较小,这样传输速度会比较快,对于集中管理的备份比较有优势.
  3. 主从,从开?因为有时候需要在从节点开一下RDB,这样可以在本地去保存这样一个历史的RDB文件,这样有一定的优势但是一定要控制他的力度不要是save自动生成的频率会很频繁,这样的话从节点不进入Redis的读写,但是所有的Redis都是一个混合部署,就是单机多部署,因为RDB是一个很重的操作,可能仍然对机器本身,例如硬盘/CPU以及内存有一定的影响,所以要根据实际开发中的实际需求来进行设定

AOF的最佳策略

  1. “开”:缓存和存储,在大部分情况先建议打开AOF,这样能特别的体现出Redis的一个特点,就是可以实时持久化,并且在大部分情况下只会丢一秒数据,大部分情况下会设置每秒区刷新磁盘.但是例如有些时候,有些缓存的场景,完全使用Redis做缓存的功能,其实里面的数据丢失了,对系统并没有任何影响,只需要下次加载的时候从数据源重新加载进来就可以,而且它对数据源的压力也没有那么大,加入你的访问对数据源没有太大的压力,这个时候其实是可以关闭掉的.毕竟 AOF确实需要一定开销的,写缓冲区等都有一定的开销的.
  2. AOF重写集中管理:单机多部署的情况下AOF集中发生,就是产生大量的fork,但是机器的内存比如是16G,我们将会分配百分之六十到七十内存给Redis,剩余20-30来给fork做一个操作用的空间,但是这部分空间并不是很大的,假如集中做fork,就可能出现内存爆满,会出现swap的情况.
  3. everysec(每秒1是刷新)

最佳策略:小分片,缓存或者存储,监控(硬盘,内存,负载,网络),足够内存

 

五.持久化的恢复

RDB 和 AOF 文件都可以用于服务器重启时来做数据恢复,具体恢复流程如图:

 

六.持久化问题的分析定位与优化

Redis持久化的功能一直是影响Redis性能的高发地,这也是我们日常工作与面试中常遇到的.

1.fork操作

当Redis做 RDB 或者 AOF 重写时,必不可少的是要进行 fork 操作,对于 大多数操作系统 来说,fork 都是一个重量级操作.虽然不会拷贝父进程所有的物理空间,但会复制父进程的空间内存页表.对于 10GB 的 Redis 进程,需要复制大约 20MB 的内存页表,因此 fork 操作耗时跟进程总内存量息息相关,如果还使用虚拟化技术,例如 Xen 虚拟机,fork 操作会更加耗时.

对于一个 Redis 实例的 OPS 在 5 万以上,如果 fork 操作耗时在秒级,那么将会拖慢几万条命令的执行,对生产环境影响明显.在正常情况下,fork操作的耗时应该是1GB/20ms左右,这个可以在 Info stats 统计中查询 latest_fork_usec 指标获取最近一次 fork 操作耗时,单位微秒.

 

优化方案:

  1. 优先使用物理机或者高效支持 fork 的虚拟化技术,避免使用 Xen.
  2. 控制 redis 实例最大可用内存,foek耗时跟内存量成正比,所以线上建议控制实力内存在 10GB 以内.
  3. 合理配置 Linux 内存分配策略,避免内存不足导致 fork 失败.
  4. 降低 fork操作 的频率,如适度放宽 AOF 自动触发时机,避免不必要的全量复制.

2.子进程开销和优化

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

1)cpu

cpu开销分析与优化

子进程负责吧进程内的数据分批写入文件,这个写入文件的过程是 CPU 密集的过程,通常子进程对单核 CPU 利用率接近 90%. 优化方法:Redis是 CPU 密集型服务,不要绑定单核 CPU,由于子进程会非常消耗CPU,所以这样会和父 CPU 进行竞争.同时,不要和其他 CPU 密集型服务部署在一个机器上。如果部署了多个 Redis 实例,尽力保证统一时刻只有一个子进程执行重写工作.

2)内存

子进程通过 fork 操作产生,占用内存大小等同于父进程,理论上需要两倍的内存完成持久化操作,但 Linux 有复制机制 (copy on write ).父子进程会共享相同的物理内存页,当父进程处理写操作时,会把要修改的页创建对应的副本,而子进程在 fork 操作过程中,共享整个父进程内存快照. 如果重写过程中存在内存修改操作,父进程负责创建所修改内存页的副本.这里就是内存消耗的地方. 优化方法:和cpu一样,如果部署多个Redis实例,尽量保证同一时刻只有一个子进程在工作;避免大量写入时做子进程重写操作,这样会导致父进程维护大量的快照副本,造成内存消耗.

3)硬盘开销分析

进程主要职责是将 RDB 或者 AOF 文件写入硬盘进行持久化,势必造成对硬盘造成压力,可通过工具例如 iostat,iotop 等工具分析重写期间硬盘负载情况.

优化方法:

(a).不要和其他高硬盘负载的服务放在一台机器上,例如 MQ,存储服务.

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

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

(d)对于单机配置多个 Redis 实例的情况,可以配置不同实例分盘存储 AOF 文件,分摊硬盘的写入压力.

3. AOF 追加阻塞

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

如图所示:

 

从上图中可以发现:everysec 配置最多可能丢失 2 秒数据,不是 1 秒;如果系统 fsync 缓慢,将会导致 Redis 主线程阻塞影响效率.

问题定位:

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

4. 单机多实例部署

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

解决方法:让所有实例的 AOF 串行执行.我们通过 info Persistence 中关于 AOF 的信息写出 Shell 脚本,然后串行执行实例的 AOF 持久化.

info Persistence片段度量指标表:

属性名

属性值
rdb_bgsave_in_progress bgsave子进程是否正在运行
rdb_current_bgsave_time_sec 当前运行bgsave的时间,-1表示未运行
aof_enabled 是否开启AOF功能
aof_rewrite_in_progress AOF重写子进程是否正在运行
aof_rewrite_scheduled 在bgsave结束后是否运行AOF重写
aof_current_rewrite_time_sec 当前运行AOF重写的时间,-1表示未运行
aof_current_size AOF文件当前字节数
aof_base_size AOF上次重写rewrite字节数

基于以上指标,可以通过外部轮询控制AOF的重写操作的执行,整个过程如图:

 

七.回顾总结

本文讲了 Redis 的持久化相关功能,例如持久化的类型,持久化每种类型的优缺点,Redis 持久化类型的选择,持久化湿如何恢复的,还有持久化问题的分析定位与优化.

 

 

参考:《redis开发与运维》,《深入分布式缓存》

版权声明:尊重博主原创文章,转载请注明出处 https://www.cnblogs.com/hsdy

posted @ 2018-11-21 16:41  寒山道杳  阅读(404)  评论(0编辑  收藏  举报