前言:持久化是什么?简单的说就是将数据放在断电后不会丢失的设备中,比如磁盘,数据库在进行写操作时做了哪些事呢?
主要有五个过程
1、客户端向服务端发送写操作(数据在客户端的内存中)。
2、数据库服务端接收到写请求的数据(数据在服务端的内存中)。
3、服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
4、操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
5、磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。
从上面可以看出,当数据库发生故障时,如果系统内核是完好的。那么执行完了第三步,那么数据就是安全的,如果断电,上面五项中所有的缓存都会失效,数据库和操作系统都会停止工作。所以只有全部走完才能保证数据不丢失。
通过上面的分析,我们可能有一些疑惑。
1、数据库多长时间调用一次write,将数据写到内核缓冲区?
2、内核多长时间会将系统缓冲区中的数据写到磁盘控制器?
3、磁盘控制器又在什么时候把缓存中的数据写到物理介质上?
其中第一个问题通常都是由数据库层面控制。第二个问题呢操作系统都有默认的策略,但是可以通过通过POSIX API提供的fsync系列命令强制操作系统将数据从内核区写到磁盘控制器上
对于第三个问题数据库已经无法触及,但实际上,大多数情况下磁盘缓存是被设置关闭的,或者是只开启为读缓存,也就是说写操作不会进行缓存,直接写到磁盘。建议的做法是仅仅当你的磁盘设备有备用电池时才开启写缓存。
数据备份一般有三种方式:
A:数据同步备份的方式
B:记录每一步的操作行为
C:以追加的方式记录数据,数据本身不修改,数据本身就是一份日志。
Redis有两种持久化策略:RDB和AOF
一、RDB快照
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照。如何生成快照呢?Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB文件。
子进程基本上是复制父进程,这等于两个相同的redis进程在系统上运行,会造成内存使用率的大幅增加。redis.conf中配置参数如下:含义为X秒改变了N次
Background saving started by pid 19064 19064:C 19 Sep 23:55:45.087 # Failed opening the RDB file dump.rdb (in server root dir /home/matao/redis-3.2.9/src) for saving: Permission denied # Will save the DB if both the given number of seconds and the given --More--(15%)2470:M 19 Sep 23:55:45.186 # Background saving error # number of write operations against the DB occurred. # # In the example below the behaviour will be to save: # after 900 sec (15 min) if at least 1 key changed # after 300 sec (5 min) if at least 10 keys changed # after 60 sec if at least 10000 keys changed # # Note: you can disable saving completely by commenting out all "save" lines. # # It is also possible to remove all the previously configured save # points by adding a save directive with a single empty string argument # like in the following example: # # save "" //保存的策略
save 900 1 save 300 10 save 60 10000
# The filename where to dump the DB dbfilename dump.rdb //保存的文件名 # The working directory. # # The DB will be written inside this directory, with the filename specified # above using the 'dbfilename' configuration directive. # # The Append Only File will also be created inside this directory. # # Note that you must specify a directory here, not a file name. dir ./ //保存的文件路径
手动保存有两种方式:
1、save 同步进行 阻塞客户端请求
2、bgsave异步进行 不妨碍目前的写入。
二、AOF
AOF是通过保存对redis服务端的写命令来记录数据库状态的,即保存你对redis数据库的写操作。AOF的运作方式是不断的将写命令追加到文件的末尾,所以随着写入命令的不断增减,AOF的文件体积也会变大越来越大。
例如:一个计数器调用了100次INCR,那么AOF文件就记录了100条记录。实际上只使用一条set命令足以保存计数器当前的值了,为了控制AOF文件的大小,redis支持执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集 所需的最少命令。
Redis调用write写入后,何时调用fsync将其写到磁盘上,通过appendfsync来控制
1、appendfsync no
当设置appendfsync为no的时候,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。
2、appendfsync everysec
当设置appendfsync为everysec的时候,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一 次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞。 所以,结论就是:在绝大多数情况下,Redis会每隔一秒进行一次fsync。在最坏的情况下,两秒钟会进行一次fsync操作。 这一操作在大多数数据库系统中被称为group commit,就是组合多次写操作的数据,一次性将日志写到磁盘。
3、appednfsync always
当设置appendfsync为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到影响。
优点:RDB非常适合用于备份,恢复速度很快。AOF会使redis变得非常耐久,使数据安全性进一步提高。
缺点:RDB在服务器故障时会丢失一段时间的数据。AOF文件的体积大于RDB,AOF的速度可能会慢于RDB。