Redis中的RDB持久化和AOF持久化(一)
来源:互联网 发布:局域网屏幕广播软件 编辑:程序博客网 时间:2024/05/17 12:56
概述
Redis是一种内存数据库,运行时数据和状态都保存在内存中,为了避免服务器进程结束而导致的数据丢失,需要将数据保存到磁盘上。Redis提供了两种策略,分别是RDB持久化和AOF持久化。本文先介绍RDB持久化。
RDB持久化
手动创建RDB文件的两个命令是SAVE和BGSAVE,他们的区别是SAVE在主进程中进行文件写入,保存时会阻塞主进程,使其不能执行任何其他操作。BGSAVE是fork一个子进程来保存,具体过程如下:
- redis调用fork,现在有了子进程和父进程。
- 父进程继续处理client请求,子进程负责将内存内容写入到临时文件。由于os的写时复制机制(copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程的地址空间内的数 据是fork时刻整个数据库的一个快照。
- 当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。
/* * 使用子进程保存数据库数据,不阻塞主进程 */int rdbSaveBackground(char *filename) { pid_t childpid; long long start; if (server.rdb_child_pid != -1) return REDIS_ERR; // 修改服务器状态 server.dirty_before_bgsave = server.dirty; // 开始时间 start = ustime(); // 创建子进程 if ((childpid = fork()) == 0) { int retval; /* Child */ // 子进程不接收网络数据 if (server.ipfd > 0) close(server.ipfd); if (server.sofd > 0) close(server.sofd); // 保存数据 retval = rdbSave(filename); if (retval == REDIS_OK) { size_t private_dirty = zmalloc_get_private_dirty(); if (private_dirty) { redisLog(REDIS_NOTICE, "RDB: %lu MB of memory used by copy-on-write", private_dirty/(1024*1024)); } } // 退出子进程 exitFromChild((retval == REDIS_OK) ? 0 : 1); } else { /* Parent */ // 记录最后一次 fork 的时间 server.stat_fork_time = ustime()-start; // 创建子进程失败时进行错误报告 if (childpid == -1) { redisLog(REDIS_WARNING,"Can't save in background: fork: %s", strerror(errno)); return REDIS_ERR; } redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid); // 记录保存开始的时间 server.rdb_save_time_start = time(NULL); // 记录子进程的 id server.rdb_child_pid = childpid; // 在执行时关闭对数据库的 rehash // 避免 copy-on-write updateDictResizePolicy(); return REDIS_OK; } return REDIS_OK; /* unreached */}
除了手动保存之外,RDB还支持自动间隔保存。如果我们用如下命令设置服务器:
save 300 1save 800 40
表示只要满足以下两个条件之一,就会执行BGSAVE命令
- 服务器在300秒之内,对数据库至少进行了1次修改
- 服务器在800秒之内,对数据库至少进行了40次修改
在服务器的结构体redisServer的saveparams数组中,保存了以上两个执行条件。另外还保存着一个dirty计数器,以及lastsave属性。dirty计数器记录了距离上一次保存之后,服务器对数据库进行了多少次修改。lastsave记录了上一次保存的时间。在周期性调用的函数serverCron中,每次都会检查dirty和lastsave,如果满足了预设的保存条件就调用BGSAVE来保存。
以下是serverCron函数中的一段代码:
/* If there is not a background saving/rewrite in progress check if * we have to save/rewrite now */ // 如果有需要,开始 RDB 文件的保存 for (j = 0; j < server.saveparamslen; j++) { struct saveparam *sp = server.saveparams+j; if (server.dirty >= sp->changes && server.unixtime-server.lastsave > sp->seconds) { redisLog(REDIS_NOTICE,"%d changes in %d seconds. Saving...", sp->changes, sp->seconds); rdbSaveBackground(server.rdb_filename);//调用BGSAVE函数 break; } }
RDB的优势
- 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这样非常方便进行备份。比如你可能打算没1天归档一些数据。
- 方便备份,我们可以很容易的将一个一个RDB文件移动到其他的存储介质上
- RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
- RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
RDB的劣势
- 如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是, 因为RDB 文件需要保存整个数据集的状态, 所以它并不是一个轻松的操作。 因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据。
- 每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。 在数据集比较庞大时, fork() 可能会非常耗时,造成服务器在某某毫秒内停止处理客户端; 如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。 虽然 AOF 重写也需要进行 fork() ,但无论 AOF 重写的执行间隔有多长,数据的耐久性都不会有任何损失。
0 0
- Redis中的RDB持久化和AOF持久化(一)
- redis持久化RDB和AOF
- REDIS持久化RDB和AOF
- redis持久化RDB和AOF
- redis持久化RDB和AOF
- redis持久化RDB和AOF
- redis持久化RDB和AOF
- redis持久化RDB和AOF
- redis----RDB和AOF持久化对比
- redis持久化RDB和AOF
- redis 持久化 RDB 和 AOF
- redis持久化rdb和aof
- redis持久化RDB和AOF
- redis持久化RDB和AOF
- redis持久化策略RDB和AOF
- redis持久化RDB和AOF
- redis持久化策略RDB和AOF
- redis持久化RDB和AOF
- PHP类库管理工具Composer入门
- 【计算机网络】TCP三次握手和四次挥手
- 利用POI在EXCEL表格中导入图片
- 正则表达式30分钟入门教程
- jquery特效插件网站
- Redis中的RDB持久化和AOF持久化(一)
- Ubuntu上安装wizi
- License数据的实时与保存
- 多线程之NSOperationQueue(线程队列)
- HDU 2059 龟兔赛跑
- 你是这样理解shell编程的嘛?
- POJ 3255 Roadblocks
- 腾讯安全零距离之大眼——大型网络流量分析系统软件篇
- win7中如何解决“该项不适用于在指定状态下使用”