码迷,mamicode.com
首页 > 其他好文 > 详细

Redis 持久化

时间:2015-08-11 21:10:15      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:

Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,例如:

(1) 将Redis作为数据库使用(存储历史数据)。

(2) 将Redis作为缓存服务器使用,如果缓存被穿透后会对性能造成很大影响,所有缓存同时失效会导致缓存雪崩,从而使服务器无法响应。

这时,我们希望Redis能将数据从内存中以某种方式同步到硬盘中,当服务器重启后可以根据硬盘中的记录恢复数据,这一过程就是持久化。

 

写操作的流程

首先我们来看一下数据库在进行写操作时到底做了哪些事,主要有下面五个过程。

1.客户端向服务端发送写操作(数据在客户端的内存中)

2.数据库服务端接收到写请求的数据(数据在服务端的内存中)

3.服务端调用write(2) 这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)

4.操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)

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会在一下几种情况下对数据进行快照:

  1. 根据配置规则进行自动快照。
  2. 用户执行save或者bgsave命令。
  3. 执行flushall命令。
  4. 执行复制时。

根据配置规则进行自动快照

你可以配置保存点,使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日志的加载

Redis 持久化

标签:

原文地址:http://www.cnblogs.com/zhangzhi19861216/p/4721846.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!