Redis之RDB和AOF持久化介绍
什么是数据库状态
redis是一个键值对的数据库服务器,服务器中通常包含中任意个非空的数据库,而每个数据库又可以包含任意个键值对,为了方便起见,我们将服务器中的非空数据库以及他们的键值对统称为数据库状态。
RDB持久化的逻辑
RDB持久化就可以手动执行也可以根据服务器配置选项定期的执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中,这个文件其实是一个二进制的文件,通过这个文件可以还原生成RDB文件时的数据库状态。
RDB文件的创建
有两个生成redisRDB文件的命令,一个是SAVE,一个是BGSAVE。SAVE命令是使用服务器进程来生成RDB文件,在生成RDB文件的时候,会阻塞所有的读写操作,服务器不能处理任何命令请求。BGSAVE命令是同过服务器进程派生出来一个子进程,然后有子进程负责创建RBD文件,服务器进程可以继续处理命令请求。
其实创建RDB文件的工作都是通过rdbsave函数实现的是不过两种命令以不同的方式调用这个函数。
SAVE命令执行时的服务器状态
其实这个很简单,我们上面已经提到过SAVE命令或阻塞一切请求,当然拥抱口BGSAVE请求了,所以在执行SAVE期间,再次执行BGSAVE命令会被直接拒绝。
BGSAVE命令执行时的服务器状态
我们知道BGSAVE命令是服务器的子进程来完成的,服务器进程可以继续接收和执行命令,但是再BGSAVE命令执行期间服务器处理SAVE、BGSAVE、BGREWRITEAOF三个命令的方式和平时有所不同,主要有一下几种情形:
1.在BGSAVE命令执行期间,客户端发起的SAVE命令会被服务器拒绝。服务器禁止SAVE命令和BGDAVE命令同时执行是为了避免父进程和子进程同时执行两个rdbsave调用,防止产生竞争条件。
2.在BGSAVE命令执行期间客户端发起BGSAVE命令会被服务器拒绝,因为同时执行两个BGSAVE命令也会产生竞争条件
3.在BGSAVE命令执行期间,客户端发起BGREWRITEAOF命令会被延迟到BGSAVE命令执行完毕之后执行
4.在BGREWRITEAOF命令执行期间,客户端发起BGSAVE命令会被服务器直接拒绝,主要是因为BGREWRITEAOF和BGSAVE命令都是由子进程来完成的,禁止他们同时执行知识一个性能方面的考虑,因为并发出两个子进程,并且这两个子进程同时进行大量的磁盘写入操作,并不是什么好事情。
RDB文件的载入
对于RDB文件的载入就相对简单了,RDB文件的载入工作是在服务器启动的时候自动执行的,并且在服务器载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成为止。
RDB自动间歇性保存
上面我们讲了如何创建RDB文件,但是什么时候来创建RBD文件呢?除了手动的执行命令之外,我们还可以通过配置来让服务器自动来创建RDB文件,我们可以在redis的配置文件中通过以下配置来实现:
save 900 1
save 300 10
save 60 10000
用户可以通过save选项设置多个保存条件(当然可以超过三个了,十个八个都可以,因为这些保存条件其实是保存在一个数组中的),但是只要其实任意一个条件满足,服务器就会执行BGSAVE命令。而上面的三条保存配置其实也是在我们开启了RDB持久化但是没有配置相关保存条件下时服务器给的默认的配置。
RDB自动保存的触发原理
我们知道了如何配置保存条件的,但是这个保存条件是怎么触发的呢?
其实服务器除了通过一个数据存储我们的保存条件外,还会维持一个dirty的计数器,以及一个lastsave属性,其中dirty计数器用来统计距离上一次成功执行SAVE命令或者BGSAVE命令后服务器对数据库状态进行了多少次修改(包括写入,删除,更新等操作),而lastsave属性是一个UNIX的时间戳,记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间。这两个值都会在成功执行完BGSAVE命令后重置:dirty重置成0,lastsave更新为当前时间。
而对于条件的判断则是Redis服务器会周期性的操作函数serverCron默认每隔100毫秒执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查save选项所设置的保存条件是否满足,如果满足则执行BGSAVe命令。必须同时满足的条件是:1.距离上一次成功执行保存的时间超过设置的时间,2.数据库状态的修改次数超过设置的修改次数
RDB的文件结构
暂略
AOF持久化的逻辑
与RBD持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存redis服务器所执行的写命令来记录数据库状态的。
被写入到AOF文件的命令都是以Redis的命令请求协议格式保存的,因为Redis的命令请求协议是纯文本的,所以我们可以直接打开一个AOF文件,里面保存的基本都是我们执行的命令,但是会有一些SELECT命令,SELECT命令是用于指定数据库的,此命令是服务器自动添加的。
AOF持久化的过程
AOF持久化过程的实现可以分为命令追加、文件写入、文件同步三个步骤。
命令追加:当AOF功能打开的时候,服务器执行一条命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区的额末尾,但是aof_buf缓冲区的命令什么时候写入aof文件这个要根据额我们的appendfsync的相关配置来决定
文件写入和同步:为了提高文件的写入效率,在现代的操作系统中,当用户调用write函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时存放到一个内存缓冲区里面,等到缓冲区满了或者超过了执行的时限之后,才真正的将缓冲区中的数据写入到磁盘里面
我们需要注意的是,Redis的服务器进程就是一个事件循环,这个循环中的文件时间负责接收客户端的命令请求,以及向客户端发送命令回复,而时间时间则负责执行向serverCron函数这样的需要定时运行的函数
因为服务器在处理文件事件时可能会执行写命令,使得这些内容被追加到aof_buf缓冲区里面,所以在服务器每次结束一个时间循环之前,它都会调用flushAppendOnlyFile函数,考虑是否需要将aof_buf缓冲区中的内容写入和保存到AOF文件里面。
flushAppendOnlyFile函数的行为是有服务器配置文件的appendfsync选项的值来决定的,appendfsync的值有三种:
1.always:将aof_buf缓冲区中的数据写入并同步到AOF文件。这种设置时最安全的,就变机器出现故障,也只是会丢失一个事件循环中所产生的命令数据
2.everysec:将aof_buf缓冲区的所有内容写入到AOF文件,如果上次同步AOF文件的时间距离现在超过1s,那么再次对AOF文件进行同步,并且这个同步操作有一个线程专门完成。这种设置,服务器在每个事件循环中都要将aof_buf缓冲区中的所有内容写入到Aof文件,并且每隔1s就要在子线程中对AOF文件进行一次同步。从效率上来讲everysec模式足够快,并且就算出现故障停机,数据库也只丢失一秒钟的命令数据。
3.no:在服务器的每个事件循环钟都要将aof缓冲区中的所有内容写入到AOF文件,但不对AOF文件进行同步,何时同步有操作系统来同步,所以这种设置是如果服务器停机,将会丢掉上次AOF文件同步后的所有写命令数据。
AOF文件的载入和数据还原
因为AOF文件中包含了重建数据库状态所需的所有写命令,所以服务器只要读入并重新执行一边AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据状态。
AOF重写
因为Aof持久化是通过保存被执行的写命令来记录数据库状态的,所以随着服务器事件的流逝,AOF文件内容会越来越大,文件体积也会也来越大,如果不加控制体积过大的AOF文件很可能对Redis服务器甚至宿主机造成影响。对于数据恢复来说,AOF文件中会有很多冗余的命令,比如对某个key操作了八次,AOF文件中会记录八条写命令,但是我们关心的只是最后一次命令执行后的数据状态,为了解决AOF文件体积膨胀问题,Redis提供了AOF重写功能。
AOF重写没有对进行AOF任何操作,只是对AOF重写时候的数据状态转成写命令保存起来,也就是说重写后的AOF文件中保存着能够换肤重写时数据库状态的最小的写命令数,这样就可以大大的减少文件的体积了。
需要注意的是在重写程序中在处理列表、哈希表、集合、有序集合这四种可能会带来多个元素的键时,会先检查包含元素的数量,如果数量超过了设置的常量值(这个值不通版本是不一样的),就会用多条命令来记录这个键而不单单时一条命令。
因为Reids是单线程的,为了不是AOF重写时阻塞服务器的正常运行,redis决定将AOF重写放到一个子进程中进行,这样做有两个好处:
1.子进程进行AOF重写期间,服务器进程(父进程)可以继续处理命令请求
2.子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用所得情况下,保证数据得安全性
有个问题我们要注意,在子进程AOF重写期间,服务器进程还需要继续处理命令请求,这个时候redis用来一个AOF重写缓冲区来解决这个问题,也就是说,在子进程AOF重写期间,服务器进程会进行三个工作:
1.执行客户端发来得命令
2.将执行后得写命令追加得AOF缓冲区
3.将执行后得写命令追加得AOF重写缓冲区
这样一来可以保证:
1.AOF缓冲区得内容会定期被写入和同步到AOF文件,对现在AOF文件得处理工作会如常进行
2.从创建子进程开始,服务器得所有写命令都会被记录到AOF重写缓冲区里面
当子进程完成AOF重写后,会向服务器进程发一个信号,并调用一个信号处理函数执行一下工作:
1.将Aof重写缓冲区中得所有内容写入到新得Aof文件中,这是新AOF文件所保存得数据库状态将和服务器当前得数据库状态保持一致
2.对新的AOF文件进行改名,原子的覆盖现在的AOF文件,完成新旧文件的交替
在整个AOF后台重写过程中,只有信号处理的时候会对服务器进程(父进程)造成阻塞,其他时候AOF后台重写都不会阻塞父进程,这将AOF重写对服务器造成的影响讲到了最低。
RDB持久化和AOF持久化的对比
RDB优劣势
优势:
- RDB只代表某个时间点上的数据快照,所以适用于备份与全量复制,如一天进行备份一次。
- Redis再加载RDB文件恢复数据远快于AOF文件
- 性能上考虑RDB优于AOF,因为我们保存RDB文件只需fork一次子进程进行保存操作,父进程没有对磁盘I/O
劣势:
- RDB没办法做到实时的持久化数据,因为fork是重量级别的操作,频繁执行成本过高
- RDB需要经常fork子进程来保存数据集到磁盘,当数据集比较大额时候,fork的过程是比较耗时的,可能会导致redis在一些毫秒级不能响应客服端请求
- 老版本的Redis无法兼容新版本的RDB文件
AOF优劣势
优势:
- 通过配置同步策略基本能够达到实时持久化数据,如配置为everysec,则每秒同步一次AOF文件,也就是说最多丢失一秒钟的数据,兼顾了性能与数据的安全性
- AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。
劣势:
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 与AOF相比,在恢复大的数据时候,RDB方式更快一些
Redis之RDB和AOF持久化介绍的更多相关文章
- redis的 rdb 和 aof 持久化的区别 [转]
aof,rdb是两种 redis持久化的机制.用于crash后,redis的恢复. rdb的特性如下: Code: fork一个进程,遍历hash table,利用copy on write,把整个d ...
- redis的 rdb 和 aof 持久化的区别
aof,rdb是两种 redis持久化的机制.用于crash后,redis的恢复. rdb的特性如下: Code: fork一个进程,遍历hash table,利用copy on write,把整个d ...
- Redis中RDB和AOF持久化区别和联系
RDB和AOF持久化 RDB持久化 RDB是什么? 原理是redis会单独创建(fork) 一个与当前进程一模一 样的子进程来进行持久化,这个子进程的所有数据(变量.环境变量,程序程序计数器等) ...
- Redis的RDB和AOF持久化
RDB 持久化:在指定的时间间隔内生成数据集的时间点快照. AOF 持久化:记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集. RDB 它只保存了 Redis 在某个 ...
- 对比 Redis 中 RDB 和 AOF 持久化
概念 Redis 是内存数据库,数据存储在内存中,一旦服务器进程退出,数据就丢失了,所以 Redis 需要想办法将存储在内存中的数据持久化到磁盘. Redis 提供了两种持久化功能: RDB (Red ...
- redis的rdb与aof持久化机制
Redis提供了两种持久化方案:RDB持久化和AOF持久化,一个是快照的方式,一个是类似日志追加的方式 RDB快照持久化 RDB持久化是通过快照的方式,即在指定的时间间隔内将内存中的数据集快照写入磁盘 ...
- Redis - 2 - 聊聊Redis的RDB和AOF持久化 - 更新完毕
1.RDB 1.1).RDB是什么? RDB,全称Redis Database RDB是Redis进行持久化的一种方式,当然:Redis默认的持久化方式也是RDB 1.2).Redis配置RDB 1. ...
- 搞懂Redis RDB和AOF持久化及工作原理
前言 因为Redis的数据都储存在内存中,当进程退出时,所有数据都将丢失.为了保证数据安全,Redis支持RDB和AOF两种持久化机制有效避免数据丢失问题.RDB可以看作在某一时刻Redis的快照(s ...
- redis 实战操作RDB和AOF快照持久化
前言:redis是我们常用的缓存方式,今天就来介绍下两种持久化的方式吧,先科普概念,再实战操作 一.RDB Redis将某一时刻的快照(备份的数据库数据)保存成一种称为RDB格式的文件中,这种格式是经 ...
随机推荐
- C语言博客作业--结构体,文件
1.本章学习总结(2分) 1.1 学习内容总结 (1)结构体如何定义.成员如何赋值 结构体的一般形式为: struct 结构体名 { 数据类型 成员名1: 数据 ...
- nRF51822 配置超过4个的 按键驱动
最近一个用到超过4个按键驱动,PCA10028 的板子上只有4个,所以SDK9 的pca10028.h 的宏只定义了4 #define BUTTONS_NUMBER 4 但是我要用超过4个的时候,就不 ...
- 【算法编程 C++ Python】二维数组查找
题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 思路: 最简单:每一行都 ...
- Monkey框架(测试方法篇) - monkey测试实例
一.常规的稳定性测试 测试背景: 这是一个海外的合作项目,被测程序是Android应用(App).测试希望通过Monkey来模拟用户长时间的随机操作,检查被测应用是否会出现异常(应用崩溃或者无响应). ...
- JAVA从服务器下载文件根据Url把多文件打包成ZIP下载
注意: 1. String filename = new String(“xx.zip”.getBytes(“UTF-8”), “ISO8859-1”);包装zip文件名不发生乱码. 2.一定要注意 ...
- Python Selenium Webdriver常用方法总结
Python Selenium Webdriver常用方法总结 常用方法函数 加载浏览器驱动: webdriver.Firefox() 打开页面:get() 关闭浏览器:quit() 最大化窗口: m ...
- 信用卡号码格式验证-C#实现
/// <summary> /// Is valid? /// </summary> /// <param name="context">Val ...
- linux hexdump使用
# hexdump -h hexdump: invalid option -- 'h' Usage: hexdump [options] file... Options: -b one-byte oc ...
- centos7.6环境编译安装php-7.2.24修复最新 CVE-2019-11043 漏洞
先编译安装php-7.2.24,然后编译安装扩展 主版本地址地址:https://www.php.net/distributions/php-7.2.24.tar.gz # 编译 php-7.2.24 ...
- Python3基础 list(dict) 使用 * 扩充时,出现字典元素重复问题
Python : 3.7.3 OS : Ubuntu 18.04.2 LTS IDE : pycharm-community-2019.1.3 ...