Redis中的RDB持久化和AOF持久化(一)
2015-04-07 19:52
169 查看
概述
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 1 save 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 重写的执行间隔有多长,数据的耐久性都不会有任何损失。
相关文章推荐
- redis之RDB持久化与AOF持久化
- Redis的两种持久化方式-快照持久化(RDB)和AOF持久化
- redis系列:RDB持久化与AOF持久化
- redis--RDB持久化--AOF持久化
- Redis的RDB持久化和AOF持久化
- redis学习之——持久化RDB 和AOF
- redis 持久化 AOF RDB
- 4、解析配置文件 redis.conf、Redis持久化RDB、Redis的主从复制
- redis-[4]-redis持久化RDB和AOF
- redis持久化RDB和AOF
- redis持久化之RDB、AOF机制比对
- redis持久化,rdb,aof
- Redis持久化————AOF与RDB模式
- redis持久化AOF与RDB配置
- redis持久化RDB和AOF
- redis之RDB持久化策略
- redis学习笔记---redis的持久化(RDB和AOF方式)
- Redis的持久化RDB
- Redis持久化RDB和AOF优缺点是什么,怎么实现的?我应该用哪一个?
- Redis提供的持久化机制(RDB和AOF)