redisRDB持久化

redisRDB持久化

转自:http://blog.csdn.net/u012658346/article/details/51385770

1、RDB文件

  Redis是一个基于内存的数据库,数据库中的所有数据都是保存在内存中的。 
  当进程退出时,内存中的数据库状态也会全部丢失。为了解决这个问题,redis提供了RDB持久化功能,RDB持久化可以将redis保存在内存中的数据存储到磁盘上,避免数据意外丢失。 
  通过该文件,可以还原RDB文件生成时的数据库状态。 
  这里写图片描述

2、RDB文件的创建

  有两个命令可以生成RDB文件:SAVE和BGSAVE。 
  其中SAVE命令会阻塞redis的服务器进程,直到RDB文件创建完毕为止。在阻塞过程中,server不能处理任何请求 
  而BGSAVE则会fork出一个子进程,然后子进程负责RDB文件的创建,父进程继续处理请求。

2.1、SAVE  

  SAVE命令最终由rdbSave()实现 
  1)首先创建rdb文件 
  2)调用rdbSaveRio()将全部数据库中全部的数据都写到rdb文件中 
  3)调用flush、sync、close将缓冲区全部刷新到文件中 
  4)将rdb文件命名为filename

 
  1. int rdbSave(char *filename) {

  2. snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());

  3. fp = fopen(tmpfile,"w");// 1、创建文件

  4.  
  5. rioInitWithFile(&rdb,fp);

  6. if (rdbSaveRio(&rdb,&error) == REDIS_ERR) {//2、写文件

  7. goto werr;

  8. }

  9.  
  10. if (fflush(fp) == EOF) goto werr; //3、刷新buffer

  11. if (fsync(fileno(fp)) == -1) goto werr;

  12. if (fclose(fp) == EOF) goto werr;

  13.  
  14. if (rename(tmpfile,filename) == -1) { //4、重命名

  15. return REDIS_ERR;

  16. }

  17. return REDIS_OK;

  18. werr:

  19. return REDIS_ERR;

  20. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.2、BGSAVE

  BGSAVE命令的实现如下: 
  1)调用fork,创建子进程 
  2)子进程调用rdbSave,相当于执行SAVE命令 
  3)父进程返回继续处理请求

 
  1. int rdbSaveBackground(char *filename) {

  2. if ((childpid = fork()) == 0) { //fork子进程

  3. /* Child */

  4. closeListeningSockets(0); //关闭监听socket

  5. redisSetProcTitle("redis-rdb-bgsave");

  6. retval = rdbSave(filename); //完成save操作

  7. exitFromChild((retval == REDIS_OK) ? 0 : 1);

  8. } else {

  9. /* Parent */

  10. if (childpid == -1) {

  11. return REDIS_ERR;

  12. }

  13. updateDictResizePolicy();

  14. return REDIS_OK;

  15. }

  16. return REDIS_OK; /* unreached */

  17. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

  当BGSAVE命令正在执行时,client端发送的SAVE、BGSAVE命令都会被server拒绝,避免产生竞争。 
  同时,当BGSAVE命令正在执行时,BGREWRITEAOF命令会被延迟到BGSAVE执行完后执行。但是如果正在执行BGREWRITEAOF时,BGSAVE命令会被拒绝

2.3、服务器自动周期性保存

  除了通过client发送SAVE、BGSAVE命令,来让server执行保存操作外,还可以通过配置服务器的save选项,让server每隔一定时间自动执行一次BGSAVE命令。 
  这里写图片描述
  这里写图片描述

3、设置保存条件

  在redisServer结构中,通过变量saveparams可以保存所有的save选项  

 
  1. struct redisServer {

  2. ......

  3. struct saveparam *saveparams; /* Save points array for RDB */

  4. int saveparamslen;

  5. long long dirty; /* Changes to DB from the last save */

  6. time_t lastsave; /* Unix time of last successful save */

  7. ......

  8. };

  9. struct saveparam {

  10. time_t seconds; //秒数

  11. int changes; //修改数

  12. };

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

  然后在serverCron()函数中 
  1)遍历参数表 
  2)将每个参数与server中保存的dirty数和lastsave时间戳进行比较 
  3)根据条件判断是否需要执行 rdbSaveBackground()完成保存操作

 
  1. int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {

  2. /* ...... */

  3. /* 判断是否正在执行BGSAVE或BGREWRITEAOF命令 */

  4. if (server.rdb_child_pid != -1 || server.aof_child_pid != -1) {

  5.  
  6. } else {

  7. /* 没有在执行BGSAVE等命令时 */

  8. for (j = 0; j < server.saveparamslen; j++) {

  9. struct saveparam *sp = server.saveparams+j;

  10.  
  11. //遍历参数表,若满足条件,则执行rdbSaveBackground

  12. if (server.dirty >= sp->changes && server.unixtime-server.lastsave > sp->seconds &&

  13. (server.unixtime-server.lastbgsave_try >REDIS_BGSAVE_RETRY_DELAY ||server.lastbgsave_status == REDIS_OK))

  14. {

  15. rdbSaveBackground(server.rdb_filename);

  16. break;

  17. }

  18. }

  19. /* ...... */

  20. }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4、RDB文件结构

  RDB文件的结构如下图所示: 
  这里写图片描述
  

  1. REDIS:为”REDIS” 5个字符,用于判断文件是否为RDB文件
  2. db_version:4字节,记录RDB文件的版本号,如0006表示第6版
  3. databases:包含0个或多个数据库,及其中所有的key-value对数据
  4. EOF:1字节,标志RDB文件正文内容的结束
  5. check_sum:8字节,由前面4部分的所有数据计算得到

 

4.1、databases部分:

  databases部分包含0个或多个数据库的内容,其中每个database的结构如下 
  这里写图片描述

  1. SELECTDB:1字节,标志后面为数据库ID
  2. db_number:数据库ID,可以为1、 2 、5字节
  3. key-value pairs:数据库中所有的key-value对数据  

 



本文所引用的源码全部来自Redis3.0.7版本

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值