Redis持久化

众所周知,Redis是内存数据库,且使用单个线程来处理命令请求。它将自己的数据库状态(非空数据库以及它们的键值对)存储在内存里面。所以如果没有持久化机制,不把数据保存到硬盘里面,那么一旦服务器进程退出,服务器中的数据库状态也会消失不见。

为了解决这个问题,redis 提供两种方法进行数据持久化,分别是RDB和AOF。RDB可以将Redis在内存中的数据库状态保存到磁盘里面以实现持久化,AOF通过记录写命令达到持久化效果。两种方法都有各自的优点,需要我们在生产环境中依照实际的业务情况进行裁定。服务器按照下面的流程图选择持久化方式:

RDB 持久化

RDB持久化既可以手动执行,也可以依据配置文件选项定期执行。RDB持久化生成的RDB文件是一个二进制文件,通过此二进制文件能够还原数据库状态。
如图:



RDB提供两种方式生成RDB文件,分别通过执行SAVE和BGSAVE命令生产RDB文件。SAVE由服务器进程直接执行保存,它会阻塞服务器的进程。BGSAVE是服务器子进程执行保存操作,它的运行不会阻塞服务器进程的运行。

SVAE 命令

上面已经说过,SAVE命令执行时会阻塞服务器的运行。因此,在服务器执行SAVE命令时,客户端发送的所有命令请求都会被拒绝。只有服务器执行完SAVE命令,服务器才会重新接收客户端发送的命令请求。

BGSAVE 命令

与SAVE相反,BGSAVE由服务器子进程执行,在执行时依然可以接收客户端发送命令并处理。但是,服务器处理SAVE、BGSAVE、BGREWRITEAOF三种方式和平时有些不一样。

  1. 对于SAVE,在执行BGSAVE时,客户端发送的SAVE命令会被服务器拒绝。服务器禁止SAVE和BGSAVE命令同时执行是为了防止父进程(服务器进程)和子进行同时执行产生竞争条件

  2. 对于BGSAVE。在执行BGSAVE时,客户端发送的BGSAVE命令时同样也是被拒绝。原因是为了防止两个BGSAVE产生竞争条件。

  3. 对于BGREWRITEAOF。在执行BGSAVE时,也是被拒绝的。原因是因为BGSAVE和BGREWRITEAOF不能同时执行。

定期持久化原理

在陈述原理之前,先来看下几个与定期持久化密切相关的属性。

  1. saveparams属性

    在服务启动后,服务器会读取save的值赋给saveparams。save 是redis.conf中的一个配置文件,它在服务器中的默认配置为:

save 900 1       //服务器在900秒之内,对数据库进行了至少1次修改。
save 300 10           //服务器在300秒之内,对数据库进行了至少10次修改。
save 60 10000         //服务器在60秒之内,对数据库进行了至少10000次修改。

服务器状态redisServer中saveparams结构如下:

      struct redisServer {    

           // ...    

           // 记录了保存条件的数组    
           struct saveparam *saveparams;   

           // ...
      };

     struct saveparam {

          // 秒数
          time_t seconds;    

          // 修改数
         int changes;
      };

如果服务器中SAVE属性为默认配置,那么服务器中的状态将会下面这样的。


  1. dirty计数器和lastsave属性 

    除了saveparams数组之外,服务器状态还维持着一个dirty计数器,以及一个lastsave属性:

  • dirty计数器记录距离上一次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态(服务器中的所有数据库)进行了多少次修改(包括写入、删除、更新等操作)。

  • lastsave属性是一个UNIX时间戳,记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间。

    dirty和lastsave在服务器状态中的结构如下:

    struct redisServer {    

           // ...    

           // 修改计数器  
            long long dirty;  

           // 上一次执行保存的时间
             time_t lastsave;  

           // ...
      };



上面已经介绍完几个重要的属性了,现在开始切入正题了。

如果未开启AOF功能,那么在Redis启动后,Redis的服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,它的其中一项工作就是检查save选项所设置的保存条件是否已经满足。如果满足的话,就执行BGSAVE命令。下面是ServerCron函数的逻辑代码

def serverCron():    
# …    
    # 遍历所有保存条件    
    for saveparam in server.saveparams:       
         # 计算距离上次执行保存操作有多少秒       
         save_interval = unixtime_now()-server.lastsave    
    
        # 如果数据库状态的修改次数超过条件所设置的次数       
        # 并且距离上次保存的时间超过条件所设置的时间        
        # 那么执行保存操作       
         if      server.dirty >= saveparam.changes and \
                   save_interval > saveparam.seconds:       
     
                BGSAVE(); 
     # ...

举个例子,如果Redis服务器的当前状态如下图所示


那么当时间来到1378271101,也即是1378270800的301秒之后,服务器将自动执行一次BGSAVE命令,因为saveparams数组的第二个保存条件——300秒之内有至少10次修改——已经被满足。

假设BGSAVE在执行5秒之后完成,那么上图所示的服务器状态将更新为下图所示的状态,其中dirty计数器已经被重置为0,而lastsave属性也被更新为1378271106。



以上就是Redis服务器根据save选项所设置的保存条件,自动执行BGSAVE命令,进行间隔性数据保存的实现原理。

AOF 持久化

AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。AOF持久化命令可以分为命令追加(append)、文件写入、文件同步三个步骤。开启AOF持久化的配置 
appendonly yes

命令追加

resist服务器中的结构是这样的

struct redisServer {
     // ...

     // AOF缓冲区
     sds aof_buf;

     // ...
}

服务器在执行一个写命令后,会将命令追加到 aof_buf 缓冲区的末尾。

命令的写入

将命令写入到aof文件中去

将aof文件中的命令同步到磁盘

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. appendfsync always (每一次写操作都会执行同步操作)
    置appendfsync为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值