Redis持久化

1.持久化简介

我们知道,Redis中的数据存在于内存中,如果Redis服务器突然宕机,数据将会全部丢失,为了解决这个问题,Redis我们提供了两种持久化机制.

什么是持久化:

利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化。 防止数据的意外丢失,确保或提高数据安全性

1610466035084

针对两种数据持久化方式,保存在硬盘中的数据不同

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

    1610466134276

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

    1610466147797

2. RDB方式

2.1 RDB手动启动方式

save指令:

save

可以使用此方式手动执行一次保存操作 ,生成RDB文件,保存信息

RDB 保存相关配置:

//dbfilename:持久化数据存储在本地的文件名为dump.rdb
//通常设置为dump-端口号.rdb
dbfilename dump.rdb

//  dir:持久化数据存储在本地的路径
dir ./

// 当snapshot时出现错误无法继续时,是否阻塞客户端“变更操作”,“错误”可能因为磁盘已满/磁盘故障/OS级别异常等 
stop-writes-on-bgsave-error yes

//设置存储至本地数据库时是否压缩数据,默认为 yes,采用 LZF 压缩
//通常默认为开启状态,如果设置为no,可以节省 CPU 运行时间,但会使存储的文件变大(巨大)
rdbcompression yes

//设置是否进行RDB文件格式校验,该校验过程在写文件和读文件过程均进行
//通常默认为开启状态,如果设置为no,可以节约读写性过程约10%时间消耗,但是存储一定的数据损坏风险
rdbchecksum yes 

在服务启动时,会自动读取RDB文件,进行数据恢复

save指令工作过程

1610547791372

如图所示,在redis过程中,如果在save指令执行时,将会阻塞排在后面的指令,直到当前RDB过程完成为止,有可能会造成长时间阻塞,线上环境不建议使用。

bgsave指令

bgsave

手动启动后台保存操作,但不是立即执行 ,Redis 进程接收到该命令后,会 fork 操作创建一个子进程,持久化过程有子进程完成。Redis 服务阻塞只会发生在 fork 阶段,而且该阶段时间过程一般都会很短。其流程如下:

1610548102059

对上述流程说明:

  1. Redis在接收到bgsave命令时,并不会立即执行,首先检查是否有正在进行的持久化子进程操作,如果有,返回2,退出
  2. 若没有,此时Redis 主线程会fork操作创建子线程,此时主线程阻塞, 创建完成后,返回信息Background saving started , 主线程继续执行其他命令, 而由子线程完成RDB操作

注意:

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

bgsave相关配置:

//后台存储过程中如果出现错误现象,是否停止保存操作 ,通常默认为开启状态
stop-writes-on-bgsave-error yes 

上面说了两种手动执行一次RDB操作的方式,但是在线上,不可以每次持久化都需要人为执行, 所以Redis还为我们提供了 自动执行的方式

2.2 RDB 自动执行方式

相关配置方式:

save second changes

满足限定时间范围内,即一个时间窗口期second秒内, key的变化数量达到指定数量changes即进行持久化 ,若在一个时间监控期内,key的改变次数没有达到指定数量, 那么本次计数将累计到下次计算

示例:

// 表示在 900s 内 ,修改过1次数据
save 900 1
//在 300s 内,修改过10次数据
save 300 10
//在60s内,修改过10000次数据
save 60 10000

注意:

  • save配置要根据实际业务情况进行设置,频度过高或过低都会出现性能问题,结果可能是灾难性的
  • save配置中自动存储的多项设置通常具有互补对应关系,尽量不要设置成包含性关系
  • save配置启动后执行的是bgsave操作 ,即不阻塞方式

RDB两种启动方式对比

方式 save指令 bgsave指令
读写 同步 异步
阻塞客户端指令
额外内存消耗
启动新进程

此外, 在如下两种情况下,也将发生自动的RDB操作

  • 服务器运行过程中重启

    debug reload
    
  • 关闭服务器时指定保存数据

    shutdown save
    

2.3 RDB 方式优缺点

RDB优点

  • RDB是一个紧凑压缩的二进制文件,存储效率较高

  • RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景

  • RDB恢复数据的速度要比AOF快很多

  • 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复。

RDB缺点:

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

3. AOF 方式

3.1 基本介绍

针对RDB不能提供实时持久化,每次执行时的性能问题等问题, 可以使用AOF来解决

AOF 即 append only file,它是将每一行对 Redis 数据进行修改的命令以独立日志的方式存储起来。在每次对Redis的操作的指令,都已日志的方式记录下来, 重启时再重新执行AOF文件中命令 达到恢复数据的目的。 它的主要目的是解决了数据持久化的实时性 ,目前已经是Redis持久化的主流方式 ,

执行过程:

Redis 在执行命令时,并不是直接记录日志文件,而是将缓冲区(aof_buf)引用进来了。将操作日志记录到其中

我们知道 Redis 是单线程的,如果每次 append aof 文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘的负载,性能肯定会受到一些影响,

那么Redis又是如何将日志从缓冲区刷入到磁盘中的呢,Redis为我们提供了三种策略

相关配置项:

// 只有在“yes”下,aof重写/文件同步等特性才会生效  ,默认关闭
appendonly no  

// 指定目录
dir ./

// 指定生成的 aof文件名称  
appendfilename appendonly.aof  

// 指定aof 同步操作日志的三种策略,有三个合法值:always everysec no,默认为everysec  
//appendfsync always  
 appendfsync everysec 
// appendfsync no 

AOF写数据三种策略(appendfsync)

  • always(每次)

    每次写入操作均同步到AOF文件中,数据零误差,性能较低 ,一般不推荐

  • everysec(每秒)

    每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高

    在系统突然宕机的情况下丢失1秒内的数据

  • no(系统控制)

    由操作系统控制每次同步到AOF文件的周期,整体过程不可控

3.2 文件重写

根据上面的介绍,可以看出,如果使用AOF的方式,那么没条操作指令,都会同步更新到日志文件中,那么随着命令的不断写入,AOF 文件会越来越庞大,

为了解决这个问题,Redis引入了AOF重写机制压缩文件体积。AOF文件重 写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将对同一个数据的若干个条命令执行结 果转化成最终结果数据对应的指令进行记录。 提高了数据恢复恢复效率 ,降低磁盘占用量

AOF重写触发方式:

  • 手动重写

    bgrewriteaof
    
  • 自动重写

    //aof文件rewrite触发的最小文件尺寸(mb,gb),只有大于此aof文件大于此尺寸是才会触发rewrite,
    auto-aof-rewrite-min-size 64mb
    // 增长百分比,此例为100,则代表当前文件大小是上次重写后文件的2倍
    auto-aof-rewrite-percentage 100  
    

    如上面这个例子代表, 如果此时AOF文件大小超过64MB,并且, (当前文件大小(aof_current_size) - 上次重写后文件大小(aof_base_size) ) / 上次重写后文件大小(aof_base_size) * 100 大于等于 100时(即增长一倍), 将会执行自动重写,
    运行指令info Persistence可以查看对应信息:

1610552242677

AOF重写规则

  • 进程内已超时的数据不再写入文件

  • 忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令

    set key1 valuel;del key1,这样的命令也是可以不用写入文件中的。

  • 对同一数据的多条写命令合并为一条命令

如lpush list1 a、lpush list1 b、 lpush list1 c 可以转化为:lpush list1 a b c。

为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素

  • 保留最终命令。

    例如 set key1 value1 set key1 value2、....set key1 valuen,类似于这样的命令,只需要保留最后一个即可

AOF 重写过程:

流程图:

1610637677774

  1. Redis 服务接收到 bgrewriteaof 命令的时候 , 主线程会fork 一个子进程执行 AOF 重写,成功后,Redis 服务继续响应命令,不会影响 Redis 原有的 AOF 流程
  2. 此时会开辟一个aof重写缓冲区,用来合并数据,并生成一个重写后的aof文件.
  3. 并且在子进程重写过程中,Redis 主进程会将受到的命令也会写入 AOF 重写缓冲区,这个缓冲区和 aof_buf 缓冲区不一样,需要区分,这样做的目的是为了防止重写过程中数据的丢失。
  4. 子进程完成重写后,使用新的aof文件替换老的,重写完毕

3.3 AOF的优缺点

优点

  • 相比于 RDB,AOF 更加安全,默认同步策略为 everysec 即每秒同步一次,所以顶多我们就失去一秒的数据
  • AOF 文件是以 append 方式写入,相比如 RDB 全量写入的方式,写入性能非常高。

缺点

  • 由于 AOF 日志文件是命令级别的,所以相比于 RDB 紧致的二进制文件而言它的加载速度会慢些。
  • AOF 开启后,Redis的吞吐量会下降一些。

4. RDB 和 AOF 对比

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

RDB与AOF的选择

  • 对数据非常敏感,建议使用默认的AOF持久化方案
  • AOF持久化策略使用everysecond,每秒钟fsync一次。该策略redis仍可以保持很好的处理性能,当出 现问题时,最多丢失0-1秒内的数据
  • 注意:由于AOF文件存储体积较大,且恢复速度较慢
  • 数据呈现阶段有效性,建议使用RDB持久化方案
    • 数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段 点数据恢复通常采用RDB方案
    • 注意:利用RDB实现紧凑的数据持久化会使Redis降的很低,慎重总结:
  • 综合比对
    • RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊
    • 如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF
    • 如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
    • 灾难恢复选用RDB

5. RDB 和 AOF 混合模式介绍

通过上面的介绍我们知道了 RDB 和 AOF 各有自己的优缺点,选择任意其一都需要接受他的缺点

有没有一种 我全都要的方式呢,

答案是有, Redis 4.0 推出了 RDB-AOF 混合持久化方案

说明:

该方案主要还是以AOF为主,但是在AOF的重写阶段,会将重写的文件头部,以RDB的方式保存当前系统的全量数据,

重写操作后, 则继续以append的方式记录在AOF文件末尾,

这样既保证了数据的安全性,又保证了Redis加载AOF文件时的速度,

要开启混合持久化需要同时将 appendonly 和 aof-use-rdb-preamble 都设置为 yes 。

更多使用细节,可以自行百度

原文地址:https://www.cnblogs.com/xjwhaha/p/14280095.html