本文是对 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 持久化深入--机制、可靠性及比较的更多相关文章

  1. 小记redis持久化的机制

    刚学redis,就经常看到两种持久化机制在眼头晃,RDB和AOF,然而当时学的还知道这两东西是啥玩意,过段时间又忘了,中文记忆这两种概念总感觉有些别扭.今心血来潮翻看redis的配置文件,豁然开朗,仿 ...

  2. redis持久化机制

    redis持久化 redis的数据存在内存中,所以存取性能好.但是存在内存中的数据存在一个问题,一旦机器重启,内存数据消失.为了解决这个问题,redis支持持久化.持久化就是为了解决内存数据丢失时恢复 ...

  3. Redis的删除机制、持久化 主从

    转: Redis的删除机制.持久化 主从 Redis的使用分两点: 性能如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存.这样,后面的请求就去缓存中读取 ...

  4. redis持久化数据的机制——转发

    转载:https://www.cnblogs.com/xingzc/p/5988080.html Redis提供的持久化机制(RDB和AOF)   Redis提供的持久化机制 Redis是一种面向“k ...

  5. 细说Redis持久化机制

    概述 Redis不仅能够作为缓存来使用,也能够作为内存数据库. Redis作为内存数据库使用时.必需要解决一个问题:数据的持久性.有些将Redis作为缓存使用的场景也需要将缓存的数据持久化到存储介质上 ...

  6. Redis持久化机制,优缺点,如何选择合适方式

    一.什么是Redis持久化? 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失. 二.Redis 的持久化机制是什么?各自的优缺点? Redis 提供两种持久化机制 RDB(默认) 和 ...

  7. redis的两种持久化的机制,你真的了解么?

    redis提供了两种持久化的机制 RDB和AOF机制 RDB(redis Database):RDB保存某一个时间点之前的快照数据. AOF(Append-Only File):指所有的命令行记录以r ...

  8. 浅谈:Redis持久化机制(一)RDB篇

    浅谈:Redis持久化机制(一)RDB篇 ​ 众所周知,redis是一款性能极高,基于内存的键值对NoSql数据库,官方显示,它的读效率可达到11万次每秒,写效率能达到8万次每秒,因为它基于内存以及存 ...

  9. 浅谈:Redis持久化机制(二)AOF篇

    浅谈:Redis持久化机制(二)AOF篇 ​ 上一篇我们提及到了redis的默认持久化方式RDB,是一种通过存储快照数据方式持久化的机制,它在宕机后会丢失掉最后一次更新RDB文件后的数据,这也是由于它 ...

随机推荐

  1. zabbix共享内存报错cannot create semaphore set

    zabbix共享内存报错 cannot open log: cannot create semaphore set: [28] No space left on device 报错原因: kernel ...

  2. 在centos6.x上安装teamviewer

    首先下载公钥: # wget http://www.teamviewer.com/link/?url=354858 # rpm --import TeamViewer_Linux_PubKey.asc ...

  3. Java 设计模式(三)-单例模式(Singleton Pattern)

    1     概念定义 1.1   定义 确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 1.2   类型 创建类模式 1.3   难点 1)多个虚拟机 当系统中的单例类被拷贝运行在多 ...

  4. springboot中filter的配置和顺序执行

    项目结构 springboot版本 <parent> <groupId>org.springframework.boot</groupId> <artifac ...

  5. 如何激活 Trend Micro Deep Security Agent

    Deep Security 即服务包括反恶意软件保护.防火墙.入侵防御系统和完整性监视.Trend Micro Deep Security Agent (DSA) 可以配合 Deep Security ...

  6. java笔记-修改javadoc为中文API信息

    Eclipse 默认的Javadoc API是英文版的,修改成中文版本的API步骤为: --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/ ...

  7. Scratch GUI

    原文地址:https://github.com/LLK/scratch-gui/wiki/Getting-Started Getting Started   Bryce Taylor edited t ...

  8. Visual Studio 2017 连接Oracle

    VS 2017 连接 Oracle 12 因为Visual Studio自带的数据文件已经不能支持超过10g以上的了,所以需要另外 下载插件 本机环境 宿主机的环境:win7,Visual Studi ...

  9. Jmeter测试普通java类说明

    概述 Apache JMeter是Apache组织开发的基于Java的压力测试工具.本文档主要描述用Jmeter工具对基于Dubbo.Zookeeper框架的Cassandra接口.区块链接口进行压力 ...

  10. + - ! function($) (), function 前面的符号意思

    如果在function之前加上感叹号 (!) 会怎么样?比如下面的代码: !function(){alert('iifksp')}()        // true 在控制台运行后得到的值时true, ...