Redis 持久化深入--机制、可靠性及比较
本文是对 antirez 博客中 Redis persistence demystified 的翻译和总结。主要从Redis的持久化机制,提供何种程度的可靠性以及与其他数据库的比较三个方面进行讨论。
0 持久化的基础:简化的写入操作步骤
在讨论持久化时,我们的最终目的是将数据保存到物理硬盘中。简化的写入操作经历如下步骤:
1. 客户端向数据库服务端发送写入或者更新数据的请求,此时数据位于客户端内存中
2. 服务端接收到写命令,此时数据位于服务端数据库应用内存中(站在服务端服务器视角,数据位于应用(数据库)内存中,即用户态内存)
3. 数据库调用系统函数向硬盘写数据,此时数据位于内核缓冲区中(kernel’s buffer)
4. 操作系统将数据从写缓冲区转移到硬盘控制器,此时数据位于硬盘缓冲区(disk cache)
5. 硬盘控制器将数据实际写入物理介质中
通常步骤2的实现因数据库的实现不同而不同,但相同的是,最终都会触发调用系统写函数进行数据写入。步骤3也因不同系统的实现而不同,但在讨论当前问题时,可将其视为单独的一步而不用关心其细节。
1 持久性(durability):什么时候才能认为数据是安全的
考虑数据安全时,我们通常考虑的是当系统发生异常时,数据是否得到了正确的保存,从而在系统恢复时能够得到恢复。考虑不同的系统异常情况:
1. 应用级的异常。这种异常是由于诸如数据库服务被异常关闭,如kill -9等。这时服务器仍旧正常运转。那么这时当上述讨论的第3步完成时,可以认为数据是安全的。因为,即使此后数据库应用被异常关闭,数据仍旧会被写入物理介质中,此后的操作已可以由操作系统独立完成。
2. 服务器级异常,例如掉电。这种情况下,只有当第5步完成时,才可以认为数据是真正安全的。
可见,对于持久化来说,关键的是上述3、4、5三个步骤的执行情况,从另一个角度考虑三个步骤的动作,他们分别表示的含义分别是:
- 数据从用户态内存向系统态内存的转移频率(write操作的调用频率)
- 系统多久将数据从系统态内存转移到硬盘控制器中
- 硬盘控制器多久将数据写入物理介质中
在第三步中,数据库可以控制通过调用系统函数write频率,但是调用该函数消耗的时间却无法得到控制。因为write函数的成功返回,依赖于写入数据量的大小及硬盘的实际写入能力,当硬盘无法实际处理写入请求时,数据会被缓存到写入缓存中,如果进一步缓存被写满,此时write调用将会阻塞,直至可以完成全部数据的写入时,write调用才会成功返回。
在第四步中,数据的转移由硬盘控制器控制,通常该写入频率不会太高,因为大量碎片数据的写入相比一次写入大数据量更慢。在Linux的默认实现中,写入间隔是30s.这意味着,当这一步失败时,最多可能有30s内的数据无法持久化到硬盘中。而在实际中,可以调用系统函数fsync强制执行该步骤。同样地,该系统调用在无法成功完成时,也会阻塞用户进程,同时也会阻塞对当前文件执行写入操作的其他进程。
第五步的实现应用层面无法控制,因此不在讨论范围内。
因此,我们关于数据库数据持久化的讨论归结为如下两个问题:
应用级,由通过write系统调用保证。
系统级,由通过fsync系统调用保证。
2 可用性:持久化数据的可用性
以上,对数据持久化从写入角度进行了讨论。此外,在讨论数据库的持久化时,还需要讨论持久化数据的可用性,即当发生异常时,持久化数据是否可以用来恢复现场。这里有三种可能:a. 数据结构被损坏,不能恢复; b. 损坏的数据可以通过一定的工具得到修复;c. 数据可用,直接加载即可。
从现有的数据库实现角度,提供如下几类数据可用性保证:
- 当某节点发生异常时,数据可以通过副本(Replica)恢复,因而持久化数据是否可用无关紧要。
- 数据的持久化通过类似日志的方式实现(比如mysql的bin-log)
- 数据的持久化通过追加模式的文件实现,这种情况下,如果对文件的写入是保证命令级原子性的,则也可以不用考虑数据损坏的情况。除非是在第5步写入时发生了系统异常。
3 Redis的持久化实现
将以上关于持久化的讨论归类为两个问题,即:
1. 持久性,即关于数据及时保存到磁盘的问题
2. 可用性,即关于持久化数据在数据库异常恢复时是否可用的问题
下面讨论Redis两种持久化方式在这两个方面的表现。
- RDB
Redis的RDB持久化方式是内存快照方式,通过对内存即时进行快照持久化实现。
持久性方面:用户可以定义当满足某种条件时即进行快照持久化,通常,考虑到性能问题,这个时间间隔会设置为分钟级。因此RDB方式并不能提供很好的持久性。
可用性方面:在不考虑首次RDB生成的情况下,首次以后的RDB文件的生成Redis的实现采用了双文件的机制,即在进行RDB时,先生成新的临时文件,当新临时文件生成完成时,通过原子性的系统函数rename进行重命名。因此,在大部分的情况下(除了首次RDB),Redis都保证RDB文件是可用的。
可见,RDB在持久性方面不够但持久化数据的可用性较好。
尽管RDB并不能提供很好的持久性保证,但是作者仍旧建议在打开AOF的同时打开RDB,并利用其进行定时数据的备份,以便在出现故障或者巨大的程序缺陷时将其做为数据恢复的基础。此外,作者还提到,RDB持久化的方式磁盘的IO在数据量确定的情况下是确定的,而不管此时数据库处理的请求情况。
- AOF
AOF通过追加日志命令的方式记录对数据产生影响的写入操作命令。
AOF方式以追加的方式进行持久化,因此提供了较好的持久化数据可用性。但是,AOF面临的问题时AOF文件的不断增长。Redis对此的解决是通过触发AOF重写来对减轻这个问题。AOF的重写类似于RDB,以内存数据为源,在AOF重写期间,先生成新的临时文件,重写期间产生的记录记录在老的AOF文件中,并在新临时文件生成后进行追加,当全部完成后进行文件替换。
持久性方面,与AOF的磁盘同步配置相关,Redis通过调用系统函数fsync实现数据的最终持久化。配置项为appendnfsync,选项有always, everysec, no,分别表示显式调用fsync函数的时机。对于常用的everysec选项,Redis至少保证2s的数据持久时间间隔,因此,最多有2s的数据是不可用的。对于always,则是命令级别;而对于no,依赖于操作系统的不同实现,Linux的默认实现中磁盘数据持久化的时间间隔为30s。
4 与其他数据库的比较
以上,首先对数据持久化的基础进行了简化抽象;然后将数据持久化问题归结为持久性及可用性两个方面,并分别对两个性质进行了解释;最后,对Redis的RDB及AOF两种持久化方式分别从持久性和可用性方面进行了考察。antirez还对PostrgreSQL与Mysql(Innodb)的持久化分别与Redis进行了比较:
假设Redis采用了AOF持久化配置,并且采用常用的appendnfsync everysec磁盘同步策略,则:
Redis提供最多不超过2s的持久性保证;
普通情况下,这个时间是1s
PostrgreSQL的持久化方面,有三个参数与Redis的持久化类似:
fsync: on/off, 打开时通过调用系统函数fsync()保证更新操作同步至磁盘。
synchronous_commit: on/local/off, 指定返回客户端’success’时,是否需要等待WAL(Write-ahead Logging:预写式日志,提供atomicity及durability保证)同步至磁盘。通常采用on 配置,如果采用off,则不保证返回的成功状态意味着写磁盘成功,通常这两步间将存在时间延迟。
wal_writer_delay: 预写式日志磁盘同步的预设延迟时间,默认为200ms,官方表示实际同步时间需要乘以3。
可见,在默认配置下,PostrgreSQL提供最坏不超过600ms的数据可用性保证。
Mysql(Innodb)的innodb_flush_log_at_trx_commit参数实现类似的控制,当设置为:
0,缓冲区将每秒写入日志文件一次并做磁盘同步,在事务提交时,不做任何动作
1,每次事务提交都将进行缓冲区到日志文件的写入,并做磁盘同步
2,事务提交时进行缓冲区到日志文件的写入,但不进行磁盘的同步
综上,antirez认为即使作为内存存储,Redis也提供了良好的持久性保证。
事实上,通过上述考察可以看出,通常作为缓存使用的Redis确实提供了良好的持久性能力(在实际应用中,很多开发者甚至都不开启持久化来获取Redis在速度方面的最大性能)。
Redis 持久化深入--机制、可靠性及比较的更多相关文章
- 小记redis持久化的机制
刚学redis,就经常看到两种持久化机制在眼头晃,RDB和AOF,然而当时学的还知道这两东西是啥玩意,过段时间又忘了,中文记忆这两种概念总感觉有些别扭.今心血来潮翻看redis的配置文件,豁然开朗,仿 ...
- redis持久化机制
redis持久化 redis的数据存在内存中,所以存取性能好.但是存在内存中的数据存在一个问题,一旦机器重启,内存数据消失.为了解决这个问题,redis支持持久化.持久化就是为了解决内存数据丢失时恢复 ...
- Redis的删除机制、持久化 主从
转: Redis的删除机制.持久化 主从 Redis的使用分两点: 性能如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存.这样,后面的请求就去缓存中读取 ...
- redis持久化数据的机制——转发
转载:https://www.cnblogs.com/xingzc/p/5988080.html Redis提供的持久化机制(RDB和AOF) Redis提供的持久化机制 Redis是一种面向“k ...
- 细说Redis持久化机制
概述 Redis不仅能够作为缓存来使用,也能够作为内存数据库. Redis作为内存数据库使用时.必需要解决一个问题:数据的持久性.有些将Redis作为缓存使用的场景也需要将缓存的数据持久化到存储介质上 ...
- Redis持久化机制,优缺点,如何选择合适方式
一.什么是Redis持久化? 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失. 二.Redis 的持久化机制是什么?各自的优缺点? Redis 提供两种持久化机制 RDB(默认) 和 ...
- redis的两种持久化的机制,你真的了解么?
redis提供了两种持久化的机制 RDB和AOF机制 RDB(redis Database):RDB保存某一个时间点之前的快照数据. AOF(Append-Only File):指所有的命令行记录以r ...
- 浅谈:Redis持久化机制(一)RDB篇
浅谈:Redis持久化机制(一)RDB篇 众所周知,redis是一款性能极高,基于内存的键值对NoSql数据库,官方显示,它的读效率可达到11万次每秒,写效率能达到8万次每秒,因为它基于内存以及存 ...
- 浅谈:Redis持久化机制(二)AOF篇
浅谈:Redis持久化机制(二)AOF篇 上一篇我们提及到了redis的默认持久化方式RDB,是一种通过存储快照数据方式持久化的机制,它在宕机后会丢失掉最后一次更新RDB文件后的数据,这也是由于它 ...
随机推荐
- MyBatis基本配置和实践(五)
第一步:创建一个Maven工程 第二步:编辑Maven工程的pom.xml,引入mybatis-generator-maven-plugin <?xml version="1.0&qu ...
- 封装网络请求并在wxml调用
https://blog.csdn.net/qq_35713752/article/details/78109084 // url:网络请求的url method:网络请求方式 data:请求参数 m ...
- Excel英语成绩单
- Linux常用基本命令大全
1 一般情况下,自己安装linux系统都会选择简易版,这里面少很多命令,所以需要安装其他的包 yum install openssh-clients 安装scp的软件包 2 把当前一 ...
- OC继承
1.成员访问类型 private:私有成员,不能被外部函数访问(使用),也不能被子类继承: protected:保护成员,不能被外部函数访问,可以被子类继承: public:公有成员,可以被外部函数访 ...
- [BZOJ 1588][HNOI 2002] 营业额统计
这果然是在那个没有STL的年代出的题 1588: [HNOI2002]营业额统计 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 16648 Solve ...
- iOS中 Proxy和的delegate区别
在ios中使用proxy代理模式,经常容易和delegate委托模式混淆. 委托模式(delegate),是简单的强大的模式,可让一个对象扮演另外对象的行为.委托对象保持到另外对象的引用,并在适当的时 ...
- 原生JS实现轮播图的效果
原生JS实现轮播图的效果: 只要缕清了全局变量index的作用,这个轮播图也就比较容易实现了:另外,为了实现轮这个效果,有几处clearInterval()必须写上.废话不多说,直接上代码,修复了几个 ...
- 使用python 操作liunx的svn,方案二
在对liunx操作svn的方式,做了改动,使用python的,subprocess进行操作 在第一种方案中,我使用了先拉到本地,然后再创建,在进行上传,实际在svn中可以直接创建文件,并进行文件复制, ...
- Django 发送html邮件
转载于: http://blog.sina.com.cn/s/blog_76e94d2101011bxd.html django中发送html邮件: #mailer.py # -*- co ...