每天用Redis,持久化方案有哪些你知道吗?

前言

  • Redis目前已经成为主流的内存数据库了,可是大部分人仅仅是停留在会用的阶段,你真的了解Redis内部的工做原理吗?面试

  • 今天这篇文章将为你们介绍Redis持久化的两种方案,文章将会从如下五个方面介绍:算法

  1. 什么是RDB,RDB如何实现持久化?sql

  2. 什么是AOF,AOF如何实现持久化?数据库

  3. AOF和RDB的区别。后端

  4. 如何重启恢复数据?安全

  5. 持久化性能问题和解决方案性能优化

RDB

  • RDB持久化是把当前进程数据生成快照保存到硬盘的过程, 触发RDB持久化过程分为手动触发和自动触发。服务器

  • RDB完成后会自动生成一个文件,保存在dir配置的指定目录下,文件名是dbfileName指定。并发

  • Redis默认会采用LZF算法对生成的RDB文件作压缩处理,压缩后的文件远远小于内存大小,默认开启。app

手动触发

  • 手动触发的命令有savebgsave

  • save:该命令会阻塞Redis服务器,直到RDB的过程完成,已经被废弃,所以线上不建议使用。

  • bgsave:每次进行RDB过程都会fork一个子进程,由子进程完成RDB的操做,所以阻塞只会发生在fork阶段,通常时间很短。

自动触发

  • 除了手动触发RDB,Redis服务器内部还有以下几个场景可以自动触发RDB:

  1. 根据咱们的 save m n 配置规则自动触发。

  2. 若是从节点执行全量复制操做, 主节点自动执行bgsave生成RDB文件并发送给从节点。

  3. 执行debug reload命令从新加载Redis时, 也会自动触发save操做。

  4. 默认状况下执行shutdown命令时, 若是没有开启AOF持久化功能则自动执行bgsave

RDB执行流程

  • RDB的主流方式就是bgsave,经过下图咱们来看看RDB的执行流程:

  • 经过上图能够很清楚RDB的执行流程,以下:

  1. 执行bgsave命令后,会先判断是否存在AOF或者RDB的子进程,若是存在,直接返回。

  2. 父进程fork操做建立一个子进程,fork操做中父进程会被阻塞。

  3. fork完成后,子进程开始根据父进程的内存生成临时快照文件,完成后对原有的RDB文件进行替换。执行lastsave命令能够查看最近一次的RDB时间。

  4. 子进程完成后发送信号给父进程,父进程更新统计信息。

RDB的优势

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

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

RDB的缺点

  • RDB方式数据没办法作到实时持久化/秒级持久化。由于bgsave每次运行都要执行fork操做建立子进程,属于重量级操做,频繁执行成本太高。

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

AOF

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

如何开启AOF

  • 开启AOF功能须要设置配置:appendonly yes, 默认不开启。AOF文件名经过appendfilename配置设置, 默认文件名是appendonly.aof。保存路径同RDB持久化方式一致,经过dir配置指定。

AOF总体的执行流程

  • AOF执行的流程大体分为命令写入文件同步文件重写重启加载四个步骤,以下图:

  • 从上图大体了解了AOF的执行流程,下面一一分析上述的四个步骤。

命令写入

  • AOF命令写入的内容直接是文本协议格式。例如set hello world这条命 令, 在AOF缓冲区会追加以下文本:

*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n
  • 命令写入是直接写入到AOF的缓冲区中,至于为何?缘由很简单,Redis使用单线程响应命令,若是每次写AOF文件命令都直接追加到硬盘, 那么性能彻底取决于当前硬盘负载。先写入缓冲区aof_buf中, 还有另外一个好处, Redis能够提供多种缓冲区 同步硬盘的策略,在性能和安全性方面作出平衡。

文件同步

  • Redis提供了多种AOF缓冲区同步文件策略, 由参数appendfsync控制,以下:

    • 配置为always时, 每次写入都要同步AOF文件, 在通常的SATA硬盘上,Redis只能支持大约几百TPS写入, 显然跟Redis高性能特性背道而驰,不建议配置。

    • 配置为no,因为操做系统每次同步AOF文件的周期不可控,并且会加大每次同步硬盘的数据量,虽然提高了性能,但数据安全性没法保证。

    • 配置为everysec(默认的配置),是建议的同步策略, 也是默认配置,作到兼顾性能和数据安全性。理论上只有在系统忽然宕机的状况下丢失1秒的数据(固然,这是不太准确的)。

文件重写机制

  • 随着命令不断写入AOF, 文件会愈来愈大, 为了解决这个问题, Redis引入AOF重写机制压缩文件体积。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。

  • 为何要文件重写呢? 由于文件重写可以使得AOF文件的体积变得更小,从而使得能够更快的被Redis加载。

  • 重写过程分为手动触发和自动触发。

    • 手动触发直接使用bgrewriteaof命令。

    • 根据auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage参数肯定自动触发时机。

  • auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积, 默认为64MB。

  • auto-aof-rewrite-percentage:表明当前AOF文件空间(aof_current_size) 和上一次重写后AOF文件空间(aof_base_size) 的比值。

  • 自动触发时机至关于aof_current_size>auto-aof-rewrite-minsize&&(aof_current_size-aof_base_size) /aof_base_size>=auto-aof-rewritepercentage。其中aof_current_sizeaof_base_size能够在info Persistence统计信息中查看。

  • 那么文件重写后的AOF文件为何会变小呢? 有以下几个缘由:

  1. 进程内已经超时的数据将不会再次写入AOF文件中。

  2. 旧的AOF文件含有无效命令,如del key1hdel key2等。重写使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令。

  3. 多条写命令能够合并为一个, 如:lpush list alpush list blpush listc能够转化为:lpush list a b c。为了防止单条命令过大形成客户端缓冲区溢出,对于listsethashzset等类型操做,以64个元素为界拆分为多条。

  • 介绍了文件重写的系列知识,下面来看看Redis内部是如何进行文件重写的,以下图:

  • 看完上图,大体了解了文件重写的流程,对于重写的流程,补充以下:

    1. 重写期间,主线程并无阻塞,而是在执行其余的操做命令,依然会向旧的AOF文件写入数据,这样可以保证备份的最终完整性,若是数据重写失败,也能保证数据不会丢失。

    2. 为了把重写期间响应的写入信息也写入到新的文件中,所以也会为子进程保留一个缓冲区,防止新写的文件丢失数据。

    3. 重写是直接把当前内存的数据生成对应命令,并不须要读取老的AOF文件进行分析、命令合并。

    4. AOF文件直接采用的文本协议,主要是兼容性好、追加方便、可读性高可认为修改修复。

    5. 不管是RDB仍是AOF都是先写入一个临时文件,而后经过重命名完成文件的替换。

    AOF的优势

    • 使用 AOF 持久化会让 Redis 变得很是耐久:你能够设置不一样的 fsync 策略,好比无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然能够保持良好的性能,而且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,因此主线程能够继续努力地处理命令请求)。

    AOF的缺点

    • 对于相同的数据集来讲,AOF 文件的体积一般要大于 RDB 文件的体积。根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。在通常状况下, 每秒 fsync 的性能依然很是高, 而关闭 fsync 可让 AOF 的速度和 RDB 同样快, 即便在高负荷之下也是如此。不过在处理巨大的写入载入时,RDB 能够提供更有保证的最大延迟时间。

    • 数据恢复速度相对于RDB比较慢。

    AOF和RDB的区别

    • RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操做过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换以前的文件,用二进制压缩存储。

    • AOF持久化以日志的形式记录服务器所处理的每个写、删除操做,查询操做不会记录,以文本的方式记录,能够打开文件看到详细的操做记录。

    重启加载

    • 不管是RDB仍是AOF均可用于服务器重启时的数据恢复,执行流程以下图:

    • 上图很清晰的分析了Redis启动恢复数据的流程,先检查AOF文件是否开启,文件是否存在,再检查RDB是否开启,文件是否存在。

    性能问题与解决方案

    • 经过上面的分析,咱们都知道RDB的快照、AOF的重写都须要fork,这是一个重量级操做,会对Redis形成阻塞。所以为了避免影响Redis主进程响应,咱们须要尽量下降阻塞。

    • 那么如何减小fork操做的阻塞呢?

    1. 优先使用物理机或者高效支持fork操做的虚拟化技术。

    2. 控制Redis实例最大可用内存, fork耗时跟内存量成正比, 线上建议每一个Redis实例内存控制在10GB之内。

    3. 合理配置Linux内存分配策略,避免物理内存不足致使fork失败。

    4. 下降fork操做的频率,如适度放宽AOF自动触发时机,避免没必要要的全量复制等。

    总结

    • 本文介绍了Redis持久化的两种不一样的策略,大部份内容是运维人员须要掌握的,固然做为后端人员也是须要了解一下,毕竟小公司都是一人搞全栈,哈哈。

    • 若是以为陈某写的不错,有所收获的话,关注分享一波,你的关注将是陈某写做的最大动力,谢谢支持!!!

    文章留言区

    往期推荐

    面试官:你知道哪几种事务失效的场景?

    每天写 order by,你知道Mysql底层执行流程吗? 万字长文带你入门Zookeeper!!! Mysql性能优化:如何给字符串加索引? SpringBoot与Maven多环境整合!!! 靓仔,整合SpringBoot还在搜配置吗?老司机教你一招!!! 老司机带你聊聊接口限流!!!

    Spring解决循环依赖,你真的懂了吗?

    老司机带你从源码开始撸Spring生命周期!!!