什么是持久化?对于持久化某度某科的解释是:程序员
持久化是将程序数据在持久状态和瞬时状态间转换的机制。通俗的讲,就是瞬时数据(好比内存中的数据,是不能永久保存的)持久化为持久数据(好比持久化至数据库中,可以长久保存)面试
因此对于持久化狭义的理解就是: “持久化”仅仅指把域对象永久保存到数据库中;能够广义的理解为:“持久化”包括和数据库相关的各类操做(持久化就是将有用的数据以某种技术保存起来,未来能够再次取出来应用,数据库技术,将内存数据一文件的形式保存在永久介质中(磁盘等)都是持久化的例子)。redis
数据持久化对象的基本操做有:保存、更新、删除、加载、查询等。数据库
保存:把域对象永久保存到数据库。缓存
更新:更新数据库中域对象的状态。安全
删除:从数据库中删除一个域对象。服务器
加载:根据特定的OID,把一个域对象从数据库加载到内存。并发
查询:根据特定的查询条件,把符合查询条件的一个或多个域对象从数据库加载内在存中。app
为何须要持久化经过前面的介绍咱们知道Redis的数据所有在内存里,因此万一出现忽然出现故障发生宕机,那么保存在内存中的数据就会所有丢失,所以必须有一种机制来保证Redis的数据不会由于故障而丢失,这种机制就是Redis的持久化机制。异步
除此以外使用数据持久化还有如下好处:
一、持久化技术封装了数据访问细节,为大部分业务逻辑提供面向对象的API。
二、程序代码重用性强,即便更换数据库,只须要更改配置文件,没必要重写程序代码。
三、业务逻辑代码可读性强,在代码中不会有大量的SQL语言,提升程序的可读性。
四、持久化技术能够自动优化,以减小对数据库的访问量,提升程序运行效率。
五、松散耦合,使持久化不依赖于底层数据库和上层业务逻辑实现,更换数据库时只需修改配置文件而不用修改代码。
如何持久化对于数据的持久化主要有如下的五个过程:
一、客户端向服务端发送写操做(数据在客户端的内存中)。
二、数据库服务端接收到写请求的数据(数据在服务端的内存中)。
三、服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
四、操做系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
五、磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。
这5个过程是在理想条件下一个正常的保存流程,可是在大多数状况下,咱们的机器等等都会有各类各样的故障,这里划分了两种状况:
(1)Redis数据库发生故障,只要在上面的第三步执行完毕,那么就能够持久化保存,剩下的两步由操做系统替咱们完成。
(2)操做系统发生故障,必须上面5步都完成才能够。
在这里只考虑了保存的过程可能发生的故障,其实保存的数据也有可能发生损坏,须要必定的恢复机制,篇幅有限这里不进行展开。
Redis对于数据的持久化一样须要经过以上五个步骤,在Redis4.x中对于数据的持久化方案主要有三种策略机制:
一、RDB(Redis DataBase)
二、AOF(Append Only File)
三、混合型方案
RDB机制RDB机制是Redis里面默认提供的一套持久化技术方案,专门用于保证内存中的数据被写入到磁盘里面去,是指在指定的时间间隔内将内存中的数据集快照写入磁盘。快照是数据存储的某一时刻的状态记录,能够理解为把当前时刻的数据保存下来,因为是某一时刻的快照,那么快照中的值要早于或者等于内存中的值。这种方式是经过修改相应的redis.conf来实现的,默认的文件名为dump.rdb。在咱们安装了redis以后,全部的配置都是在redis.conf文件中,里面保存了RDB和AOF两种持久化机制的各类配置。
好比:
redis.config中的语句主要是用于将数据持久化在redis的dump.rdb文件里面,而后每一次开启redis的时候都会将里面的数据从新加载,进行数据恢复。dump.rdb的存放位置由下边的dir来标识。
前面说了RDB机制是经过把某个时刻的全部数据生成一个快照来保存,既然是快照那么就应该有一种触发机制,来触发快照的功能。对于RDB来讲,提供了三种机制来触发快照,分别是:save、bgsave、自动触发机制。
rdb里面并非单纯将数据直接存储起来,而是经过一种特定的lzf压缩方式来实现的:
这个配置开关最好打开,默认是开启的,不然会致使rdb文件过大,占用磁盘空间。
触发rdb存储机制的条件有两种:
一、执行save指令:这是一种阻塞式指令,阻塞当前redis服务器,直RDB过程完成为止。若是内存比较大会形成redis长时间阻塞,因此线上禁止使用。具体流程能够总结以下:
二、执行bgsave命令:执行该命令时,Redis会在后台异步进行快照操做,快照同时还能够响应客户端请求。具体操做是redis进程执行fork操做建立子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,时间通常很短,具体和实例数据大小有关系。具体流程能够总结以下:
除了执行上面的两种命令手动触发以外,redis还存在如下4种方式自动触发RDB的持久化机制。
一、使用save相关配置,如“save m n” 表示m秒内数据集存在n次修改时,自动触发bgsave。也能够同时配置多个条件,只要其中一个达标就触发。
config文件中save机制的配置以下:
save <指定时间间隔> <执行指定次数更新操做> (默认是save 900 1)
能够理解为指定的秒内若是进行了指定次数的更新操做,就会将数据存储到dump.rdb文件中去。
二、主从复制时,从节点执行全量复制操做,主节点自动执行bgsave生成RDB文件并发送给从节点;
三、执行debug reload命令时从新加载redis
四、默认状况下执行shutdown命令时,若是没有开启aof持久化则自动执行bgsave
每项技术都会有必定的优势和缺点,RDB的优缺点能够总结以下:
优势:
一、RDB适合大规模的数据恢复。
二、RDB是一个紧凑压缩的二进制文件,占用的内存比较小,表明数据在某一个时间点的快照。很是适合备份,全景复制。好比每三个小时执行bgsave备份,并把RDB文件上传到备份服务器中,用于防止Redis服务器不可恢复性问题。
三、RDB恢复数据速度快于AOF的方式。
四、RDB 能够最大化 redis 的性能。父进程在保存 RDB 文件时惟一要作的就是 fork 出一个子进程,而后这个子进程就会处理接下来的全部保存工做,父进程无须执行任何磁盘 I/O 操做。
五、RDB 很是适用于灾难恢复(disaster recovery),由于它只有一个文件,而且内容都很是紧凑,能够(在加密后)将它传送到别的数据中心。
缺点:
一、RDB 在服务器故障时容易形成数据的丢失。RDB容许经过修改配置来控制持久化的频率。可是,由于RDB文件须要保存整个数据集的状态,因此它是一个比较繁重的操做,若是频率太频繁,会对Redis性能产生必定的影响。因此通常能够设置至少5分钟才保存一次快照,这时若是 Redis 出现宕机等状况,也就意味着最多可能丢失5分钟数据。因此数据的完整性和一致性不高。
二、备份时会占用内存。由于Redis 在备份时会独立建立一个子进程而且采用的是 copy-on-write 的方式,在 Redis 执行 RDB 持久化期间,若是 client 写入数据很频繁,那么将增长 Redis 占用的内存,最坏状况下,内存的占用将达到原先的2倍。刚 fork 时,主进程和子进程共享内存,可是随着主进程须要处理写操做,主进程须要将修改的页面拷贝一份出来,而后进行修改。极端状况下,若是全部的页面都被修改,则此时的内存占用是原先的2倍。
三、若是数据比较大时,备份的时候会比较耗时RDB 保存时使用 fork 子进程进行数据的持久化时,若是数据比较大的话,fork 可能会很是耗时,形成 Redis 中止处理服务N毫秒。若是数据集很大且 CPU 比较繁忙的时候,中止服务的时间甚至会到一秒。
四、同上由于bgsave每次运行都要执行fork操做建立子进程,属于重量级操做,频繁执行成本太高,因此RDB方式数据没办法作到实时持久化/秒级持久化。
五、由于RDB文件使用特定二进制格式保存,Redis版本演进过程当中有多个格式的RDB版本,因此存在老版本Redis服务没法兼容新版RDB格式的问题。
AOF机制前面说了虽然RDB可以做为redis的持久化进行数据的备份,可是也存在一些不足。因此为了弥补RDB的缺点,aof机制应势而出。aof的全称是append only file,它是以独立日志的形式来将每一次写操做都进行记录,追加到相应的文件中去。Redis重启的时候会根据日志文件的内容从前到后执行一次达到数据恢复的目的。前面说到RDB有个缺点就是数据备份的实时性比较低,因此AOF的主要做用是解决了数据持久化的实时性,目前AOF已是Redis持久化的主流。
在conf文件中一样有对于aof的配置:
appendonly:默认值为no,由于r前面说过Redis 默认使用的是rdbd的持久化方式,若是想要开启 AOF 持久化方式,须要将 appendonly 修改成 yes。
appendfilename :指的是aof文件名,默认是"appendonly.aof"
appendfsync:aof持久化策略的配置,可取的值有三种:always、everysec和no。
设置为always时,会极大消弱Redis的性能,由于这种模式下每次write后都会调用fsync立马将数据写入磁盘进行持久化(Linux为调用fdatasync)。虽然性能差,可是安全性是最高的。
设置为no时,则write后不会有fsync调用,由操做系统自动调度刷磁盘,直接写入aof的内存缓冲区,性能是最好的。
设置为everysec时,最多每秒调用一次fsync,这种模式性能并非很糟糕,通常也不会产生毛刺,这归功于Redis引入了BIO线程,全部fsync操做都异步交给了BIO线程。这也是推荐的策略模式,就如同配置说明上说的:If unsure, use "everysec"(若是不肯定就是使用everysec)。
它们三个能够总结为:
策略 | 写回时机 | 优势 | 缺点 |
Always | 同步写回 | 数据基本不会丢失,可靠性好 | 每一个命令都要写入磁盘,性能较差 |
No | 系统控制 | 性能好 | 安全性差,宕机时丢失数据较多 |
Everysec | 每秒写回 | 性能中等 | 宕机时丢失一秒内的数据 |
AOF里触发该机制的条件能够在conf文件里面进行配置:
当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留能够恢复数据的最小指令集。
配置参数:
auto-aof-rewrite-min-size 64mb
表示aof文件要达到必定体积才会进行重写
auto-aof-rewrite-percentage 100
表示当aof文件大小增加了100%才会触发重写
重写的原理
aof在进行重写处理的时候,会额外开辟一个bgrewriteaof线程,将原先的aof文件数据拷贝到一个临时文件进行处理,最后再覆盖原先文件。AOF文件重写过程与RDB快照bgsave工做过程有点类似,都是经过fork子进程,由子进程完成相应的操做,一样的在fork子进程简短的时间内,redis是阻塞的。具体过程以下图所示:
相比于rdb而言,aof的数据备份效率更高,可是在数据恢复的时候其性能却远远不如rdb高效。
混合型策略重启 Redis 时,若是采用rdb来恢复内存状态,会丢失大量数据。
若是使用 aof,性能相对rdb来讲要慢不少,这样在Redis数据很大的状况下,启动的时候时间消耗比较大。
混合型策略是Redis4.0开始添加的新的混合型持久化方案。混合型方案就是将前面的RDB持久化方案以及AOF持久化方案结合。
混合持久化一样也是经过bgrewriteaof完成的,不一样的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,而后在将aof_rewrite_buf重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。能够简单的理解为:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,能够理解为:
这样作的好处是能够结合 rdb 和 aof 的优势, 快速加载同时避免丢失过多的数据,而缺点是 aof 里面的 rdb 部分就是压缩格式再也不是 aof 格式,可读性差。
混合持久化默认关闭的,能够经过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是禁用的。
aof-use-rdb-preamble yes # yes:开启,no:关闭
若是开启了混合策略,那么在启动redis时依然优先加载aof文件进行数据恢复,而aof文件加载可能有两种状况以下:
一、若是aof文件开头是rdb的格式, 先加载 rdb内容再加载剩余的 aof。
二、若是aof文件开头不是rdb的格式,直接以aof格式加载整个文件。
虽然混合策略是rdb和aof结合的,可是它有优势一样也还有必定的缺点:
优势:
混合持久化结合了RDB持久化 和 AOF 持久化的优势, 因为绝大部分都是RDB格式,加载速度快,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。
缺点:
兼容性差,一旦开启了混合持久化,在4.0以前版本都不识别该aof文件。
同时因为前部分是RDB格式,阅读性较差。
总结以上主要介绍了redis对数据进行持久化的三种策略,分别是:RDB、AOF以及基于其两种方案的混合型持久策略。这三种策略都有本身的优势和缺点,实际使用中能够根据实际的场景和需求进行合理的选择。
最后最近我整理了整套《JAVA核心知识点总结》,说实话 ,做为一名Java程序员,不论你需不须要面试都应该好好看下这份资料。拿到手老是不亏的~个人很多粉丝也所以拿到腾讯字节快手等公司的Offer
进【Java进阶之路群】,找管理员获取哦-!