Redis(三):Redis的两种持久化方式

1、RDB持久化

  1.1 手动执行

  1.2 定期执行

2、AOF持久化

  2.1  AOF持久化的实现

  2.2  AOF数据的载入和还原

  2.3  AOF重写


    redis有两种持久化方式,分别是RDB持久化和AOF持久化,RDB持久化通过保存数据库中的键值对来保存数据库的状态,而AOF持久化是通过保存服务器执行的写命令来保存数据库的状态。

1、RDB持久化

    RDB持久化既可以手动执行,也可以根据服务器的配置选项定期执行,该功能可以将某个时间点上的数据库保存到一个RDB文件中。

1.1 手动执行

    手动执行有两个命令可以生成RDB文件,分别是:

  • SAVE:SAVE命令会阻塞服务器进程,知道RDB文件创建完毕为止。在服务器阻塞期间,服务器不能处理任何命令请求。
  • BGSAVE:BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求。在BGSAVE命令执行期间,服务器处理SAVE、BGSAVE和BGREWRITEAOF三个命令和平时有所不同。首先在BGSAVE命令执行期间,客户端发送的SAVE命令和BGSAVE命令会被拒绝执行。此外,BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行。如果BGREWRITEAOF命令正在执行,那么客户端发送的BGSAVE命令会被服务器拒绝。BGREWRITEAOF和BGSAVE都由子进程去执行,他两不能同时执行的原因只是一个性能方面的考虑,并发出两个子进程会执行大量的磁盘IO操作。

   需要注意的是,在redis启动时,因为AOF的更新频率要比RDB的更新频率高,所以,如果AOF功能开启,服务器会优先使用AOF来还原数据库的状态。只有在AOF持久化功能处于关闭时,服务器才会使用RDB文件来还原数据库的状态。

扫描二维码关注公众号,回复: 13048312 查看本文章

1.2 定期执行

    由于BGSAVE命令是在子进程中执行的,所以redis允许用户通过设置服务器的配置选项save让服务器没隔一段时间自动执行一次BGSAVE。举个例子:

save 900 1
save 300 10
save 60 10000

 只要满足以下三个条件中的任何一个,BGSAVE命令就会被执行: 

  • 900s内,对服务器至少执行了一次写修改
  • 300s内,对服务器进行了至少10次写修改
  • 60s内,对服务器进行了至少10000次修改

    此外,服务器还维护着一个dirty计数器和一个lastsave属性:

  • dirty计数器记录距离上一次成功执行SAVE或者BGSAVE命令之后,服务器对数据库状态执行了多少次修改;
  • lastsave属性是一个UNIX时间戳,记录了服务器上一次成功执行SAVE或者BGSAVE的时间。

2、AOF持久化

2.1  AOF持久化的实现

    服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器的aof_buf缓冲区的末尾。服务器在每次结束一个事件循环之前,它都会调用flushAppendOnlyFile这个函数,考虑是否要将aof_buf的缓冲区的内容写入和保存到AOF文件中。该函数的行为由配置的appendfsync选项的值来决定。

  • always:每个事件循环都将缓冲区的内容写到aof文件中,并且同步aof文件,即执行操作系统的fsync函数;
  • everysec:每个事件循环都将缓冲区的内容写到aof文件中,并且每隔1s就在子线程中对aof文件进行同步一次,执行一次fsync函数;
  • no:每个事件循环都将缓冲区的内容写到aof文件中,至于何时对aof文件进行同步,由操作系统决定。

2.2  AOF数据的载入和还原

 服务器读取AOF文件并还原数据库状态的详细步骤如下:

(1)创建一个不带网络连接的伪客户端。因为redis的命令只能在客户端的上下文中执行,所以redis使用一个不带网络连接的伪客户端来执行aof文件保存的写命令;

(2)从aof文件分析并读取一条写命令;

(3)使用伪客户端执行读出的写命令;

(4)一直执行步骤(2)和步骤(3)直到AOF的写命令全部执行完。

2.3  AOF重写

    因为AOF持久化是通过保存被执行的写命令来记录数据库状态的,所以随着服务器运行,AOF文件的内容会越来越多,文件的体积会越来越大。为了解决AOF文件膨胀问题,redis提供了AOF文件重写功能。通过该功能,redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新文件中不会包含任何冗余的命令。

(1)AOF重写的实现

    AOF重写主要是由aof_rewrite这个函数来实现的。该函数执行时,首先从数据库读取键现在的值,然后用一条命令去记录键值对,代替之前记录这个键值对的多条命令,这就是AOF重写功能的实现原理。

(2)AOF后台重写

    由于aof_rewrite命令会进行大量的写入操作,而redis服务器采用单线程实现,如果服务器调用aof_rewrite函数的化,在重写期间,服务器将无法处理客户端发来的命令请求。所以redis决定将AOF重写程序放到子进程中执行,手动后台重写主要通过BGREWRITEAOF这个命令来实现。这样做有两个好处:

  • 子进程对AOF重写期间,服务器进程可以继续处理命令请求。
  • 子进程带有服务器进程的数据副本,使用子进程而不是线程,可以避免使用锁的情况下,保证数据的安全性。

    不过使用子进程也有一个问题,因为子进程在执行AOF重写期间,服务器还要处理客户端请求,而新的命令会对现有数据进行修改,从而是的当前的数据库状态和AOF保存的数据库状态不一致。为了解决这个问题,redis服务器设置了一个AOF重写缓冲区,这个缓冲区在创建子进程后使用,当redis执行完了一个写命令之后,它会同时将这个写命令发送给AOF缓冲区和AOF重写缓冲区,这样可以保证:

  • 子进程中AOF缓冲区的内容会定期写入和同步到AOF文件中,对现有的AOF文件的处理工作会如常进行
  • 创建子进程开始,服务器执行的所有写命令都会记录到AOF重写缓冲区里面

    当子进程完成重写之后,它会向父进程发送一个信号,父进程收到这个信号后,会调用一个信号处理函数,并执行以下工作:

  • 将AOF重写缓冲区的所有内容写到新的AOF文件中
  • 对新的AOF文件进行改名,原子地覆盖现有的AOF文件,完成新旧两个AOF文件的替换。

   这个信号处理完成之后,父进程就可以像往常一样接收命令请求了。在整个AOF后台重写过程中,只有信号处理函数会对服务器进程造成阻塞,其他时候都不会阻塞父进程,这将AOF重写对服务器性能造成的影响降到了最低。

(3)AOF自动后台重写

    主要通过判断配置文件的auto-aof-rewrite-percentage这个参数,当满足条件时,AOF会进行自动后台重写。

猜你喜欢

转载自blog.csdn.net/MOU_IT/article/details/113098724