redis学习笔记(17)---RDB持久化
来源:互联网 发布:读取身份证照片软件 编辑:程序博客网 时间:2024/05/21 06:48
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
int rdbSave(char *filename) { snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid()); fp = fopen(tmpfile,"w");// 1、创建文件 rioInitWithFile(&rdb,fp); if (rdbSaveRio(&rdb,&error) == REDIS_ERR) {//2、写文件 goto werr; } if (fflush(fp) == EOF) goto werr; //3、刷新buffer if (fsync(fileno(fp)) == -1) goto werr; if (fclose(fp) == EOF) goto werr; if (rename(tmpfile,filename) == -1) { //4、重命名 return REDIS_ERR; } return REDIS_OK;werr: return REDIS_ERR;}
2.2、BGSAVE
BGSAVE命令的实现如下:
1)调用fork,创建子进程
2)子进程调用rdbSave,相当于执行SAVE命令
3)父进程返回继续处理请求
int rdbSaveBackground(char *filename) { if ((childpid = fork()) == 0) { //fork子进程 /* Child */ closeListeningSockets(0); //关闭监听socket redisSetProcTitle("redis-rdb-bgsave"); retval = rdbSave(filename); //完成save操作 exitFromChild((retval == REDIS_OK) ? 0 : 1); } else { /* Parent */ if (childpid == -1) { return REDIS_ERR; } updateDictResizePolicy(); return REDIS_OK; } return REDIS_OK; /* unreached */}
当BGSAVE命令正在执行时,client端发送的SAVE、BGSAVE命令都会被server拒绝,避免产生竞争。
同时,当BGSAVE命令正在执行时,BGREWRITEAOF命令会被延迟到BGSAVE执行完后执行。但是如果正在执行BGREWRITEAOF时,BGSAVE命令会被拒绝
2.3、服务器自动周期性保存
除了通过client发送SAVE、BGSAVE命令,来让server执行保存操作外,还可以通过配置服务器的save选项,让server每隔一定时间自动执行一次BGSAVE命令。
3、设置保存条件
在redisServer结构中,通过变量saveparams可以保存所有的save选项
struct redisServer { ...... struct saveparam *saveparams; /* Save points array for RDB */ int saveparamslen; long long dirty; /* Changes to DB from the last save */ time_t lastsave; /* Unix time of last successful save */ ...... }; struct saveparam { time_t seconds; //秒数 int changes; //修改数};
然后在serverCron()函数中
1)遍历参数表
2)将每个参数与server中保存的dirty数和lastsave时间戳进行比较
3)根据条件判断是否需要执行 rdbSaveBackground()完成保存操作
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { /* ...... */ /* 判断是否正在执行BGSAVE或BGREWRITEAOF命令 */ if (server.rdb_child_pid != -1 || server.aof_child_pid != -1) { } else { /* 没有在执行BGSAVE等命令时 */ for (j = 0; j < server.saveparamslen; j++) { struct saveparam *sp = server.saveparams+j; //遍历参数表,若满足条件,则执行rdbSaveBackground if (server.dirty >= sp->changes && server.unixtime-server.lastsave > sp->seconds && (server.unixtime-server.lastbgsave_try >REDIS_BGSAVE_RETRY_DELAY ||server.lastbgsave_status == REDIS_OK)) { rdbSaveBackground(server.rdb_filename); break; } } /* ...... */}
4、RDB文件结构
RDB文件的结构如下图所示:
- REDIS:为”REDIS” 5个字符,用于判断文件是否为RDB文件
- db_version:4字节,记录RDB文件的版本号,如0006表示第6版
- databases:包含0个或多个数据库,及其中所有的key-value对数据
- EOF:1字节,标志RDB文件正文内容的结束
- check_sum:8字节,由前面4部分的所有数据计算得到
4.1、databases部分:
databases部分包含0个或多个数据库的内容,其中每个database的结构如下
- SELECTDB:1字节,标志后面为数据库ID
- db_number:数据库ID,可以为1、 2 、5字节
- key-value pairs:数据库中所有的key-value对数据
本文所引用的源码全部来自Redis3.0.7版本
redis学习参考资料:
https://github.com/huangz1990/redis-3.0-annotated
Redis 设计与实现(第二版)
- redis学习笔记(17)---RDB持久化
- redis 源码学习(RDB 持久化)
- Redis持久化RDB与AOF(笔记)
- Redis 学习 ---- 10.RDB持久化
- Redis RDB持久化
- Redis RDB持久化
- redis持久化--rdb
- Redis-RDB持久化
- redis- 持久化-rdb
- 【redis】RDB 持久化
- redis持久化RDB
- RDB(redis db)持久化
- redis的持久化(RDB/AOF)
- Redis的持久化(RDB&&AOF)
- Redis持久化之RDB(二)
- Redis数据库持久化(RDB/AOF)
- Redis 持久化之RDB(二)
- 结合redis设计与实现的redis源码学习-12-RDB持久化(rdb.h/rio.h)
- hdu1978 How many ways(DP)
- 酷炫的下载的进度动画2
- 搬家通知博文地址
- mac x Yosemide(10.10) 下安装 jdk 1.7 (jdk 1.8) 要求Mac OS X10.7.3或更高版本解决
- 839 - Not so Mobile
- redis学习笔记(17)---RDB持久化
- Arrays.Tostring
- 选择排序1到100
- HDU 2544 最短路(Dijkstra算法)
- Linux系统中postgresql双机热备(流复制)
- 用Android访问本地站点---(localhost,10.0.2.2)要区别
- Android学习--《数据的保存》
- 冒泡排序
- CY7C68013A Slave FIFO 相关的寄存器