redis提供了两种持久化方式。
aof(APPEND ON FILE)持久化:原理是将redis的操作以命令的方式写入aof文件中,追加。
rdb(Redis DataBase)内存快照持久化,就是将redis的内存中的数据全量拷贝一份存储在磁盘中。
我们来详细的分析下这两种持久化方式。
1. aof持久化
aof持久化是将reids的每次执行成功后的命令记录到aof文件中。
执行成功后记录AOF日志,可以保证每次记录的AOF命令都是正确的,错误就直接返回给客户端。 AOF的文件中是如何记录的呢? 我们以redis的一个成功记录的命令为例:
set test 'hello world'
aof日志内容中*3表示 此命令由三部分组成【set,test,hello world】,每部分都是以$+数字开头,后面跟上命令、键或者值。其中数字表示后面跟的命令、键或者值的长度(字节)。例如 “$4 test”表示这部分有4个字节,就是 test。
如图所示
redis提供了三种aof写回策略
1. always 同步回写:每条命令执行完成后,回立即将日志写回磁盘。
2. everysec 每秒回写:每个命令执行完后回先将日志写入aof文件的内存缓冲区,每隔一秒把缓冲区中的命令写入磁盘
3. no 操作系统控制的回写:每个写命令执行完后只是先把日志写入aof文件的内存缓冲区,何时回写磁盘由操作系统决定。
分析:
always回写回占用主线程资源,每次回写都是一个慢速的罗盘操作,基本上可以避免数据的丢失,会对主线程产生影响,如果你对redis数据的准确性要求非常高,而写入和读取占比不高的话,可以采用这种策略。
每秒回写采用一秒回写一次的策略,避免了同步回写的性能开销,虽然减少了对系统性能的影响,但是如果1秒内产生了大量的写操作,在aof缓冲区积压了很多日志,这时候还没来得及写入aof日志文件就发生了宕机,就会造成数据的丢失。
采用操作系统控制的回写,在写完aof缓冲区后就可以继续执行命令,但是如果系统发生宕机了,也同样会造成数据的丢失。
aof日志本身由哪些性能问题呢?
aof日志是以文件形式将命令存储到磁盘中,如果修改的频繁,redis的数据库也比较大的时候,就会造成aof文件日志过大。
文件过大会造成以下三个方面的问题:
如果redis服务器发生重启的时候,依靠aof文件去恢复数据库就会导致执行的时间过长,会对性能产生影响。
文件系统对文件的大小本身就有大小限制。
文件过大,再往里面加内容的时候,就会变慢。
如何解决这种问题呢?
redis提供了aof重写机制,aof日志是把所有写命令记录下来,如果对一个键值对做十次修改,则就会记录十次,aof重写机制就是把这条键值对的多次操作压缩成一次操作,这样就大大减少了aof日志文件的大小。
尽管aof重写机制大大缩小了aof文件的大小,如果redis数据库本身的数据就比较庞大的时候aof重写也会占用很多时间。
aof重写会阻塞吗?
aof日志的重写是由后台程序bgrewriteaof子进程完成的,这也是为了避免阻塞主线程,导致数据性能下降。
在重写的时候,redis主进程会fork出一个bgrewriteaof子进程,bgrewriteaof会在不影响主进程的情况下完成回写。
如果在回写的过程中,主进程有命令写入怎么办?
如果有新的写入,主进程会在老的aof缓冲区写入,也会在新的aof文件缓冲区写入,这样就算重写失败,老的aof数据也不会丢失,新的aof文件重写完成后,可以把aof文件缓冲区再次写入aof中,新的aof也不会丢失文件。
2. RDB日志
RDB持久化方式时以内存快照的方式把文件存储到磁盘中,文件是以.rdb结尾,里面存储的是二进制数据。
两种RDB存储方式
save:save 是需要占用主线程资源的,会阻塞主线程。
bgsave:使用的是子进程写,不会占用主线程的资源(fork会阻塞主线程,但是copyonwrite过程是纳秒级别相对较快,aof是毫秒级别)。
redis为了数据的可靠性,每次rdb的时候都是全量快照。
如果redis在执行快照的时候,有数据写入了怎么办?
redis使用了操作系统的写时复制技术(COPY -ON-WRITE COW)
bgsave子进程是由主进程fork生成的,可以共享主进程的内存,如果主进程有写入命令时候,主进程会把写入的那块内存页先复制一份给fork使用,这样就不影响主进程的写操作,可以继续修改原来的数据,避免了对正常业务的影响。