Redis的强劲性能很大程度上是因为其将全部数据都存储在了内存中,为了使Redis在重启以后仍能保证数据不丢失,例如:redis
(1) 将Redis做为数据库使用(存储历史数据)。数据库
(2) 将Redis做为缓存服务器使用,若是缓存被穿透后会对性能形成很大影响,全部缓存同时失效会致使缓存雪崩,从而使服务器没法响应。缓存
这时,咱们但愿Redis能将数据从内存中以某种方式同步到硬盘中,当服务器重启后能够根据硬盘中的记录恢复数据,这一过程就是持久化。安全
写操做的流程服务器
首先咱们来看一下数据库在进行写操做时到底作了哪些事,主要有下面五个过程。app
1.客户端向服务端发送写操做(数据在客户端的内存中)异步
2.数据库服务端接收到写请求的数据(数据在服务端的内存中)性能
3.服务端调用write(2) 这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)编码
4.操做系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)lua
5.磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)
写操做大体有上面5个流程,下面咱们结合上面的5个流程看一下各类级别的故障。
•当数据库系统故障时,这时候系统内核仍是OK的,那么此时只要咱们执行完了第3步,那么数据就是安全的,由于后续操做系统会来完成后面几步,保证数据最终会落到磁盘上。
•当系统断电,这时候上面5项中提到的全部缓存都会失效,而且数据库和操做系统都会中止工做。因此只有当数据在完成第5步后,机器断电才能保证数据不丢失,在上述四步中的数据都会丢失。
经过上面5步的了解,可能咱们会但愿搞清下面一些问题:
•数据库多长时间调用一次write(2),将数据写到内核缓冲区
•内核多长时间会将系统缓冲区中的数据写到磁盘控制器
•磁盘控制器又在何时把缓存中的数据写到物理介质上
对于第一个问题,一般数据库层面会进行全面控制。而对第二个问题,操做系统有其默认的策略,可是咱们也能够经过POSIX API提供的fsync系列命令强制操做系统将数据从内核区写到磁盘控制器上。对于第三个问题,好像数据库已经没法触及,但实际上,大多数状况下磁盘缓存是被设置关闭的。或者是只开启为读缓存,也就是写操做不会进行缓存,直接写到磁盘。建议的作法是仅仅当你的磁盘设备有备用电池时才开启写缓存。
所谓数据损坏,就是数据没法恢复,上面咱们讲的都是如何保证数据是确实写到磁盘上去,可是写到磁盘上可能并不意味着数据不会损坏。好比咱们可能一次写请求会进行两次不一样的写操做,当意外发生时,可能会致使一次写操做安全完成,可是另外一次尚未进行。若是数据库的数据文件结构组织不合理,可能就会致使数据彻底不能恢复的情况出现。
这里一般也有三种策略来组织数据,以防止数据文件损坏到没法恢复的状况:
1.第一种是最粗糙的处理,就是不经过数据的组织形式保证数据的可恢复性。而是经过配置数据同步备份的方式,在数据文件损坏后经过数据备份来进行恢复。
2.另外一种是在上面基础上添加一个操做日志,每次操做时记一下操做的行为,这样咱们能够经过操做日志来进行数据恢复。由于操做日志是顺序追加的方式写的,因此不会出现操做日志也没法恢复的状况。
3.更保险的作法是数据库不进行老数据的修改,只是以追加方式去完成写操做,这样数据自己就是一份日志,这样就永远不会出现数据没法恢复的状况了。
针对上述数据库写操做流程及数据库文件组织策略,咱们来认识Redis的持久化
Redis支持两种方式的持久化
一种是RDB(快照)方式,一种是AOF(追加文件)方式。能够单独使用其中一种或将两者结合使用。
RDB
RDB方式的持久化是经过快照(snapshotting)完成的,当符合必定条件时Redis会自动将内存中的全部数据生成一份副本并存储在硬盘上,这个过程即为“快照”。Redis会在一下几种状况下对数据进行快照:
根据配置规则进行自动快照
你能够配置保存点,使Redis若是在每N秒后数据发生了M次改变就保存快照文件。例以下面这个保存点配置表示每60秒,若是数据发生了1000次以上的变更,Redis就会自动保存快照文件:
save 60 1000
保存点能够设置多个,Redis的配置文件就默认设置了3个保存点:
# 格式为:save <seconds> <changes>
# 能够设置多个。
save 900 1 #900秒后至少1个key有变更
save 300 10 #300秒后至少10个key有变更
save 60 10000 #60秒后至少10000个key有变更
若是想禁用快照保存的功能,能够经过注释掉全部"save"配置达到,或者在最后一条"save"配置后添加以下的配置:
save ""
文件路径和名称
默认Redis会把快照文件存储为当前目录下一个名为dump.rdb的文件。要修改文件的存储路径和名称,能够经过修改配置文件redis.conf实现:
# RDB文件名,默认为dump.rdb。
dbfilename dump.rdb
# 文件存放的目录,AOF文件一样存放在此目录下。默认为当前工做目录。
dir ./
用户执行save或者bgsave命令
除了让Redis进行自动快照外,当进行服务器重启,手动迁移以及备份的时候咱们也须要手动执行快照操做,redis提供了两命令:
save 命令执行一个同步保存操做,将当前 Redis 实例的全部数据快照(snapshot)以 RDB 文件的形式保存到硬盘。
通常来讲,在生产环境不多执行 SAVE 操做,由于它会阻塞全部客户端,保存数据库的任务一般由 BGSAVE 命令异步地执行。
bgsave 命令执行以后当即返回 OK ,而后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,而后退出。
客户端能够经过 LASTSAVE 命令查看最近一次成功执行快照的时间,返回一个unix时间戳。
Flushall命令
flushall清空整个 Redis 服务器的数据(删除全部数据库的全部 key )。注意:不管清空数据库的过程是否触发了自动快照条件,只要自动快照条件不为空,redis就会执行一次快照。例如:当定义快照条件为1秒内修改10000个键时进行快照,而是据库只有一个健,执行flushall也会触发快照,即便这一过程只有一个健被修改。当没有定义自动快照条件时,执行fluahall命令不进行快照。
执行复制
当设置了主从模式时,redis会在复制初始化时进行自动快照,即便没有自定义自动快照条件,而且没有手动执行过快照操做,也会生成RDB快照文件。
快照原理
1.redis 使用 fork 命令复制一份当前进程(父进程)的副本(子进程)
2.父进程继续接受并处理客户端发来的命令,而子进程开始将内存的数据存储写入硬盘的临时文件
3.当子进程写入完全部数据后调用将临时文件替换旧的 RDB 文件,到这里一次快照结束。
RBD 明显的不足就是一旦数据库出现崩溃之类的,RDB 里保存的数据可能不是最新的,从上次 RDB 到 redis 停机这段时间的数据可能会丢失。
AOF
Redis 将全部对数据库进行过写入的命令(及其参数)记录到 AOF 文件, 以此达到记录数据库状态的目的为了方便起见, 咱们称呼这种记录过程为同步。
开启AOF方式持久化:
appendonly yes
AOF文件的保存位置和RDB文件位置相同,默认appendonly.aof,可经过appendfilename参数修改:
Appendfilename appendonly.aof
同步硬盘数据
根据“写的操做流程”可知,虽然每次执行更改数据库内存操做时,AOF都会将命令记录在AOF文件中,可是根据操做系统缓存机制,数据并无真正地写入硬盘。通常来说启用AOF的应用没法容忍这样的损失,这就须要Redis在写入AOF文件后主动将系统缓存同步到硬盘中。
Redis 能够经过appendfsync 参数设同步的时机:
#appendfsync always #每次执行都同步
appendfsync everysec #每秒执行一次同步,默认
#appendfsync no # 不主动同步操做,由操做系统决定(30秒一次)
Redis 容许同时开启AOF和RDB,重启时会使用AOF文件恢复数据,由于AOF方式可能丢失的数据更少。
从上面看出,RDB和AOF操做都是顺序IO操做,性能都很高。而同时在经过RDB文件或者AOF日志进行数据库恢复的时候,也是顺序的读取数据加载到内存中。因此也不会形成磁盘的随机读。
到底选择什么呢?下面是来自官方的建议:一般,若是你要想提供很高的数据保障性,那么建议你同时使用两种持久化方式。若是你能够接受灾难带来的几分钟的数据丢失,那么你能够仅使用RDB。不少用户仅使用了AOF,可是咱们建议,既然RDB能够时不时的给数据作个完整的快照,而且提供更快的重启,因此最好仍是也使用RDB。在数据恢复方面:RDB的启动时间会更短,缘由有两个:一是RDB文件中每一条数据只有一条记录,不会像AOF日志那样可能有一条数据的屡次操做记录。因此每条数据只须要写一次就好了。另外一个缘由是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不须要再进行数据编码工做,因此在CPU消耗上要远小于AOF日志的加载