Redis目前已经成为主流的内存数据库了,可是大部分人仅仅是停留在会用的阶段,你真的了解Redis内部的工做原理吗?面试
今天这篇文章将为你们介绍Redis持久化的两种方案,文章将会从如下五个方面介绍:算法
什么是RDB,RDB如何实现持久化?sql
什么是AOF,AOF如何实现持久化?数据库
AOF和RDB的区别。后端
如何重启恢复数据?安全
持久化性能问题和解决方案性能优化
RDB持久化是把当前进程数据生成快照保存到硬盘的过程, 触发RDB持久化过程分为手动触发和自动触发。服务器
RDB完成后会自动生成一个文件,保存在dir
配置的指定目录下,文件名是dbfileName
指定。并发
Redis默认会采用LZF算法对生成的RDB文件作压缩处理,压缩后的文件远远小于内存大小,默认开启。app
手动触发的命令有save
和bgsave
。
save
:该命令会阻塞Redis服务器,直到RDB的过程完成,已经被废弃,所以线上不建议使用。
bgsave
:每次进行RDB过程都会fork一个子进程,由子进程完成RDB的操做,所以阻塞只会发生在fork阶段,通常时间很短。
除了手动触发RDB,Redis服务器内部还有以下几个场景可以自动触发RDB:
根据咱们的 save m n
配置规则自动触发。
若是从节点执行全量复制操做, 主节点自动执行bgsave生成RDB文件并发送给从节点。
执行debug reload
命令从新加载Redis时, 也会自动触发save操做。
默认状况下执行shutdown命令时, 若是没有开启AOF持久化功能则自动执行bgsave
。
RDB的主流方式就是bgsave,经过下图咱们来看看RDB的执行流程:
经过上图能够很清楚RDB的执行流程,以下:
执行bgsave命令后,会先判断是否存在AOF或者RDB的子进程,若是存在,直接返回。
父进程fork操做建立一个子进程,fork操做中父进程会被阻塞。
fork完成后,子进程开始根据父进程的内存生成临时快照文件,完成后对原有的RDB文件进行替换。执行lastsave
命令能够查看最近一次的RDB时间。
子进程完成后发送信号给父进程,父进程更新统计信息。
RDB是一个紧凑压缩的二进制文件, 表明Redis在某个时间点上的数据快照。很是适用于备份, 全量复制等场景。好比每6小时执行bgsave
备份,并把RDB文件拷贝到远程机器或者文件系统中,用于灾难恢复。
Redis加载RDB
恢复数据远远快于AOF
的方式。
RDB方式数据没办法作到实时持久化
/秒级持久化
。由于bgsave每次运行都要执行fork操做建立子进程,属于重量级操做,频繁执行成本太高。
RDB文件使用特定二进制格式保存, Redis版本演进过程当中有多个格式的RDB版本, 存在老版本Redis服务没法兼容新版RDB格式的问题。
AOF
(append only file) 持久化:以独立日志的方式记录每次写命令,重启时再从新执行AOF文件中的命令达到恢复数据的目的。AOF的主要做用是解决了数据持久化的实时性, 目前已是Redis持久化的主流方式
。
开启AOF功能须要设置配置:appendonly yes
, 默认不开启。AOF文件名经过appendfilename
配置设置, 默认文件名是appendonly.aof
。保存路径同RDB持久化方式一致,经过dir
配置指定。
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-size
和auto-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_size
和aof_base_size
能够在info Persistence
统计信息中查看。
那么文件重写后的AOF文件为何会变小呢? 有以下几个缘由:
进程内已经超时的数据将不会再次写入AOF文件中。
旧的AOF文件含有无效命令,如del key1
、 hdel key2
等。重写使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令。
多条写命令能够合并为一个, 如:lpush list a
、 lpush list b
、lpush listc
能够转化为:lpush list a b c
。为了防止单条命令过大形成客户端缓冲区溢出,对于list
、 set
、 hash
、 zset
等类型操做,以64个元素为界拆分为多条。
介绍了文件重写的系列知识,下面来看看Redis内部是如何进行文件重写的,以下图:
看完上图,大体了解了文件重写的流程,对于重写的流程,补充以下:
重写期间,主线程并无阻塞,而是在执行其余的操做命令,依然会向旧的AOF文件写入数据,这样可以保证备份的最终完整性,若是数据重写失败,也能保证数据不会丢失。
为了把重写期间响应的写入信息也写入到新的文件中,所以也会为子进程保留一个缓冲区,防止新写的文件丢失数据。
重写是直接把当前内存的数据生成对应命令,并不须要读取老的AOF文件进行分析、命令合并。
AOF文件直接采用的文本协议
,主要是兼容性好、追加方便、可读性高可认为修改修复。
不管是RDB
仍是AOF
都是先写入一个临时文件,而后经过重命名
完成文件的替换。
使用 AOF 持久化会让 Redis 变得很是耐久:你能够设置不一样的 fsync 策略,好比无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然能够保持良好的性能,而且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,因此主线程能够继续努力地处理命令请求)。
对于相同的数据集来讲,AOF 文件的体积一般要大于 RDB 文件的体积。根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。在通常状况下, 每秒 fsync 的性能依然很是高, 而关闭 fsync 可让 AOF 的速度和 RDB 同样快, 即便在高负荷之下也是如此。不过在处理巨大的写入载入时,RDB 能够提供更有保证的最大延迟时间。
数据恢复速度相对于RDB比较慢。
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操做过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换以前的文件,用二进制压缩存储。
AOF持久化以日志的形式记录服务器所处理的每个写、删除操做,查询操做不会记录,以文本的方式记录,能够打开文件看到详细的操做记录。
不管是RDB仍是AOF均可用于服务器重启时的数据恢复,执行流程以下图:
上图很清晰的分析了Redis启动恢复数据的流程,先检查AOF文件是否开启,文件是否存在,再检查RDB是否开启,文件是否存在。
经过上面的分析,咱们都知道RDB的快照、AOF的重写都须要fork,这是一个重量级操做,会对Redis形成阻塞。所以为了避免影响Redis主进程响应,咱们须要尽量下降阻塞。
那么如何减小fork操做的阻塞呢?
优先使用物理机或者高效支持fork操做的虚拟化技术。
控制Redis实例最大可用内存, fork耗时跟内存量成正比, 线上建议每一个Redis实例内存控制在10GB之内。
合理配置Linux内存分配策略,避免物理内存不足致使fork失败。
下降fork操做的频率,如适度放宽AOF自动触发时机,避免没必要要的全量复制等。
本文介绍了Redis持久化的两种不一样的策略,大部份内容是运维人员须要掌握的,固然做为后端人员也是须要了解一下,毕竟小公司都是一人搞全栈,哈哈。
若是以为陈某写的不错,有所收获的话,关注分享一波,你的关注将是陈某写做的最大动力,谢谢支持!!!
文章留言区
往期推荐
每天写 order by,你知道Mysql底层执行流程吗? 万字长文带你入门Zookeeper!!! Mysql性能优化:如何给字符串加索引? SpringBoot与Maven多环境整合!!! 靓仔,整合SpringBoot还在搜配置吗?老司机教你一招!!! 老司机带你聊聊接口限流!!!Spring解决循环依赖,你真的懂了吗?