所谓的redis的持久化也就是数据落地,对于任何一个数据系统都要考虑是不是需要数据落地。在系统崩溃或是机房掉电等的情况下,将有用的数据记录在非易失性存储器上面,防止数据丢失,以及用来系统重启时的数据恢复。
对于一般的写操作,他的大致流程如下面几个过程:
- 1.客户端向服务端发送写操作(数据在客户端的内存中)
- 2.数据库服务端接收到写请求的数据(数据在服务端的内存中)
- 3.服务端调用write(2) 这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)
- 4.操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)
- 5.磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)
针对上面的过程可以知道,数据的写操作实际上是会涉及到应用程序缓存、内核缓存,磁盘控制器缓存的三级缓存。当应用程序崩溃之前只要成功调用了write,数据就会被转移到内核,这时只要系统还是正常运行的,内核就会保证将数据写入硬盘。但是当系统掉电以后,所有的数据就停留在了掉电之前最后一刻的状态。所以就会存在下面几个问题:
- 数据库多长时间调用一次write,将数据写到内核缓冲区
- 内核多长时间会将系统缓冲区中的数据写到磁盘控制器
- 磁盘控制器又在什么时候把缓存中的数据写到物理介质上
要保证数据真正写入到磁盘,应用程序可以控制的就只有应用程序缓存,内核缓冲(fsync)。对于上面第一个问题,通常应用程序会进行全面控制。而对第二个问题,操作系统有其默认的策略,但是我们也可以通过POSIX API提供的fsync系列命令强制操作系统将数据从内核区写到磁盘控制器上。但是对于第三个问题,应用程序就已经无法触及,但实际上,大多数情况下磁盘缓存是被设置关闭的。或者是只开启为读缓存,也就是写操作不会进行缓存,直接写到磁盘。建议的做法是仅仅当你的磁盘设备有备用电池时才开启写缓存。
要保证数据的持久性,redis提供了两种方式:RDB快照和AOF日志文件。Redis支持将当前数据的快照存成一个数据文件的持久化机制,redis借助fork的COW(copy on write)机制,在生成快照的时候,fork出一个子进程,在子进程中遍历所有数据,将数据写成rdb文件。Redis的RDB快照机制可以配置成“多长时间内有多少次的修改操作就生成快照”,也可以通过命令动态的配置。但是,很明显,RDB存在一个问题就是,一旦redis出现问题,rdb文件保存的数据不是最新的,也就是在上次快照和数据库故障之间的数据会丢失,这在某些应用中是不能容忍的,所以也就有了AOF日志文件的持久化机制。
AOF日志的全称是append only file,他是将每次成功的修改操作添加到日志文件中,就像mysql中的binlog日志,但是不同的是,binlog日志是二进制形式存储的,而AOF是文本形式的,他会以文本的形式将操作的命令记录下来,如以星号(*)开头,后跟本次操作的argc,后跟argc个长度和字符对,其中长度以$符号开头,命令或参数则前面没有任何符号。但是单纯的这种AOF机制还是存在问题,那就是如果系统一直运行,那么AOF文件会持续增大,并且会有很多重复的记录,所以redis实现了采用了AOF重写的机制来解决这个问题。他就像RDB机制一样,会适时的fork一个进程,遍历所有的数库重新生成一个AOF文件,来替代以前的文件,这样,就会避免重复,减小AOF文件的大小。但是注意AOF机制实际上是一个写文件的操作,所有就会有最开始提到的问题,能否将write的数据正真写到磁盘上,为此,redis提供了三种形式:appendfsync no/everysec/always。No表示不执行fsync调用,使用操作系统默认的策略,这种形式则完全依赖于操作系统,everysec则是没隔一秒执行一次fsync强制写磁盘,always则表示每次执行write之后都执行一次fsync调用。分析上面的三种策略可以看出,no的话,程序不能控制,everysec则有可能丢失一秒以内的数据,而always会保存所有的数据但是会损失性能。所以在选择持久化的时候需要进行权衡。
一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快,因为对于RDB只要将数据载入内存,就形成了所有的数据结构,恢复了数据库,但是对于AOF来讲,他不但要将数据载入内存,还要依赖一个fakeclient执行载入的命令,之后才能恢复数据库。
对于RDB和AOF,还有一个很重要的地方需要注意,那就是这两种形式的写磁盘都是顺序写,顺序I/O性能都很高,而且在恢复的时候也是顺序读,所以整个过程不会造成随机读写磁盘。
参考:
http://www.searchdatabase.com.cn/showcontent_59739.htm
http://my.oschina.net/davehe/blog/174662