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

1、RDB持久化

    1.1 RDB手动执行  

    1.2 RDB定期执行

2、AOF持久化

    2.1  AOF持久化的实现

    2.2  AOF数据的载入

    2.3  AOF重写


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

1、RDB持久化

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

1.1 RDB手动执行

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

(1)SAVE

    SAVE命令会阻塞服务器进程,直到RDB文件创建完毕为止。在服务器阻塞期间,服务器不能处理任何命令请求。

(2)BGSAVE

    BGSAVE命令会fork出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求。子进程在把所有键值对保存到RDB文件之后,会向父进程发送一个退出的信号,父进程每次时间事件调用serverCron函数时,都会以非阻塞的方式调用wait()函数,判断子进程是否发送出信号,从而处理一些子进程执行结束之后的善后工作。在BGSAVE命令执行期间,服务器处理SAVE、BGSAVE和BGREWRITEAOF三个命令和平时有所不同。

  • 在BGSAVE命令执行期间,客户端发送的SAVE命令和BGSAVE命令会被拒绝执行,BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行。
  • 在BGREWRITEAOF命令正在执行,那么客户端发送的BGSAVE命令会被服务器拒绝。

    BGREWRITEAOF和BGSAVE都由子进程去执行,他两不能同时执行的原因只是一个性能方面的考虑,并发出两个子进程会执行大量的磁盘IO操作。需要注意的是,在redis启动时,因为AOF的更新频率要比RDB的更新频率高,所以,如果AOF功能开启,服务器会优先使用AOF来还原数据库的状态。只有在AOF持久化功能处于关闭时,服务器才会使用RDB文件来还原数据库的状态。

1.2 RDB定期执行

    由于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的时间。

    BGSAVE的定期执行主要是在时间事件serverCron函数中调用的,serverCron函数每次调用时,都会检查BASAVE执行的条件是否满足,如果满足设置的条件,则会后台执行BGSAVE命令。

2、AOF持久化

2.1  AOF持久化的实现

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

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

2.2  AOF数据的载入

   服务器在启动时,初始化的最后一步就是要从磁盘中加载持久化的文件,调用的函数为loadDataFromDisk,其流程如下:

      

   由于RDB文件的持久化频率远低于AOF持久化的频率,AOF持久化一般是每次进入事件循环之前,都会进行一次AOF持久化,而RDB持久化只有在满足一定的条件之后才会进行。因此从文件中加载数据库的数据时,如果打开了AOF持久化的功能,那么优先从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重写既可以通过手动执行,也可以通过配置文件配置好参数定期执行:

  • 手动执行:主要通过BGREWRITEAOF这个命令来实现
  • 定期执行:主要通过判断配置文件的auto-aof-rewrite-percentage这个参数,当满足条件时,AOF会进行自动后台重写。

(2)AOF后台重写

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

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

(3)AOF重写缓冲区

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

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

    

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值