Redis持久化

文章目录

  • 前言
  • 一、RDB持久化
  • 二、AOF持久化
    • 1.如何保证写入数据的安全性
    • 2.如何解决AOF文件体积问题
    • 3.如何解决AOF重写期间数据的一致性
  • 三、RDB和AOF优缺点
  • 四、RDB和AOF如何选择
  • 五、Redis 4.0 混合日志模型


前言

因为Redis是内存数据库,它将自己的数据库状态存储在内存里面,所以如果不想办法将存储在内存中的数据库状态保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据库状态也会消失不见。
Redis为了解决这个问题,提供了两种持久化方式。一种是RDB,另一种是AOF方式。前者会根据规则“定时”将内存中的数据保存储在磁盘上,而后者在每次执行命令后将命令的本身记录下来。


一、RDB持久化

RDB持久化是通过快照(snapshoting)完成的,当符合一定的条件时,Redis会自动将内存中的数据保存到磁盘上。Redis会在以下几种情况下对Redis进行快照:

  1. 执行save命令:save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器阻塞期间,服务器不能处理任何命令请求。
  2. 执行bgsave命令:会调用glbc的函数fork产生一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求。
  3. 自动间隔性保存:因为bgsave命令可以在不阻塞服务器进程的情况下执行,所以Redis允许用户通过设置服务器配置的save选项,让服务 器每隔一段时间自动执行一次bgsave命令。
    比如我们在服务器配置如下:
    save 900 1
    save 300 10
    save 60 10000
    那么只要满足以下三个条件中的任意一个,Bgsav命令就会被执行:
    服务器在900秒以内,对数据库进行了至少1次修改。
    服务器在300秒以内,对数据库进行了至少10次修改。
    服务器在60秒以内,对数据库进行了至少10000次修改。
  4. 执行FLUSHALL命令:Redis Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。执行该命令也会生成Rdb文件。
  5. 执行复制(replication)时。
  6. Redis停机时。

二、AOF持久化

AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。
为了提高文件写入效率,在现代操作系统中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满,或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。

1.如何保证写入数据的安全性

缓冲区这种做法虽然提供了效率,但是也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。

为此,系统提供了fsync和fdatasync两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。

Redis提供的AOF配置项appendsync写回策略直接决定AOF持久化功能的效率和安全性。

  1. 当appendsync 的值为always时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,并且同步AOF文件,所以always的效率是appendsync选项三个值当中最慢的一个,但从安全性来说,always也是最安全,因为即使出现故障停机,AOF持久化也只丢失一个事件循环中所产生的命令数据。
  2. 当appendsync的值为everysec时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,并且每隔一秒就要在子进程中对AOF文件进行一次同步。所以从效率上来讲,everysec模式足够快,并且就算出现故障停机,数据库也只丢失一秒中的命令数据。
  3. 当appendsync的值为no时,服务器在每个事件循环都要将aof_buf缓冲区中的所有内容写入到AOF文件,至于何时对AOF文件进行同步,则由操作系统控制。

所以想要获得⾼性能,就选择 No 策略; 如果想要得到⾼可靠性保证,就选择 Always 策略;如果允许数据有⼀点丢失,⼜希望性能别受太⼤影响的话,那 么就选择 Everysec 策略。

2.如何解决AOF文件体积问题

因为AOF持久化是通过保存被执行的写命令来记录数据库状态的,所以随着服务器运行事件的流逝,AOF文件中的内容会越来越多,文件的体积也会越来越大。

为了解决AOF文件体积膨胀的问题,Redis提供了AOF文件重新功能。通过该功能,Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件。

AOF文件重写并不需要对现有的AOF文件进行任何读取,分析或者写入操作,这个功能是通过读取服务器当前的数据库状态来实现的。
比如服务器对list键执行了以下命令:
RPUSH list “A” “B”
RPUSH list “C”
RPUSH list “D” “E”
LPOP list
LPOP list
RPUSH list “F” “G”

正常情况下需要在AOF文件中写入六条命令。而为了减少AOF文件中的命令数量,首先从数据库中读取键现在的值,然后用一条命令区记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理。比如上面这个合并成一条命令为:
RPUSH list “C” “D” “E” “F” “G” 来代替保存在AOF文件中的六条命令。

命令合并又会带来一个新的问题,比如重写程序在处理列表,哈希表,集合,有序集合这四种可能带有多个元素的键时,假设合并后命令太长,那么就会造成客户端输入缓冲区溢出。AOF重写是如何解决这个问题的呢?

在重写之前,会先检查键所包含的元素数量,如果超过了64个元素,那么重写程序会多条命令来记录,并且每条命令设置的元素数量也为64个。
AOF重写数据的一致性:
在重写AOF文件的时候,为了避免客户端阻塞,Redis将AOF重写程序放到子进程里执行,这样可以达到两个目的:
子进程进行AOF重写期间,服务器进程(父进程)可以继续处理命令请求。
子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性。

3.如何解决AOF重写期间数据的一致性

不过使用子进程也有一个问题需要解决,因为子进程在进行AOF重写期间,服务器进程还需要继续处理命令请求,而新的命令可能会对现有的数据库状态进行修改,从而使的服务器当前的数据库状态和重写后的AOF文件所保存的数据库状态不一致。

为了解决这种数据不一致的问题,Redis服务器设置了一个AOF重写缓冲区。

在子进程进行AOF重写期间,如果服务器执行了相应的写命令,会吧这些写命令都记录到AOF重写缓冲区里。当子进程完成AOF重写工作之后,它会向父进程发送一个信号,父进程在接到该信号之后,将AOF重写缓冲区中所有的内容写入到AOF文件中,这时新AOF文件所保存的数据库状态将和服务器当前的数据库状态一致。

三、RDB和AOF优缺点

RDB
优点:
• RDB快照是一个压缩过的非常紧凑的文件,保存着某个时间点的数据集,适合做数据的备份,灾难恢复;
• 可以最大化Redis的的性能,在保存RDB文件,服务器进程只需要fork一个子进程来完成RDB文件的创建,父进程不需要做IO操作;
• 与AOF相比,恢复大数据集的时候会更快;
缺点:
• RDB的数据安全性是不如AOF的,保存整个数据集的过程是比繁重的,根据配置可能要几分钟才快照一次,如果服务器宕机,那么就可能丢失几分钟的数据;
• Redis数据集较大时,fork的子进程要完成快照会比较耗CPU、耗时;
AOF
优点:
• 数据更完整,安全性更高,秒级数据丢失(取决fsync策略,如果是everysec,最多丢失1秒的数据);
• AOF文件是一个只进行追加的日志文件,且写入操作是以Redis协议的格式保存的,内容是可读的,适合误删紧急恢复;
缺点:
• 对于相同的数据集,AOF文件的体积要大于RDB文件,数据恢复也会比较慢;
• 根据所使用的fsync策略,AOF的速度可能会慢于RDB。 不过在一般情况下,每秒fsync的性能依然非常高;

四、RDB和AOF如何选择

通常来说,应该同时使用两种持久化方案,以保证数据安全。
• 如果数据不敏感,且可以从其他地方重新生成,可以关闭持久化。
• 如果数据比较重要,且能够承受几分钟的数据丢失,比如缓存等,只需要使用RDB即可。
• 如果是用做内存数据,要使用Redis的持久化,建议是RDB和AOF都开启。
• 如果只用AOF,优先使用everysec的配置选择,因为它在可靠性和性能之间取了一个平衡。
当RDB与AOF两种方式都开启时,Redis会优先使用AOF恢复数据,因为AOF保存的文件比RDB文件更完整

五、Redis 4.0 混合日志模型

重启 Redis 时,我们很少使用rdb 来恢复内存状态,因为会丢失⼤量数据。我们通常使⽤ AOF ⽇志重放,但是重 放 AOF ⽇志性能相对 rdb 来说要慢很多,这样在 Redis 实例很⼤的情况下,启动需要花费很⻓的时间。
Redis 4.0 为了解决这个问题,带来了⼀个新的持久化选项——混合持久化。将 rdb ⽂件的内容和增量的 AOF ⽇志 ⽂件存在⼀起。这⾥的 AOF ⽇志不再是全量的⽇志,⽽是⾃持久化开始到持久化结束的这段时间发⽣的增量 AOF ⽇志,通常这部分 AOF ⽇志很⼩。 于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF ⽇志就可以完全替代之前的 AOF 全量⽂ 件重放,重启效率因此⼤幅得到提升。 所以 RDB 内存快照以稍微慢⼀点的频率执⾏,在两次 RDB 快照期间使⽤ AOF ⽇志记录期间发⽣的所有「写」操 作。 这样快照就不⽤频繁的执⾏,同时由于 AOF 只需要记录两次快照之间发⽣的「写」指令,不需要记录所有的操 作,避免出现⽂件过⼤的情况。

你可能感兴趣的:(Java,redis,数据库,服务器)