本文是对 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. day04之VUE痛悟

    vue组件组件分为三部分

  2. openresty及lua的随机函数

    我们都知道,所谓的随机都是伪随机,随机的结果是由随机算法和随机种子决定的. 所以,当我们没有初始化的时候,如果直接使用math.random(),那么出来的值肯定是每次都一样,因为种子等于0. 因此, ...

  3. December 24th 2016 Week 52nd Saturday

    The first step is as good as half over. 第一步是最关键的一步. If one goes wrong at the first steps, what shoul ...

  4. pipenv

    一. 1. 使用pip安装pipenv及其相关依赖 pip install pipenv 2. 将目录更改为包含你的Python项目的文件夹,并启动Pipenv cd my_project pipen ...

  5. 导出当前域内所有用户hash的技术整理

    0x00目标: 导出当前域内所有用户的hash 0x01测试环境: 域控:server2008 r2 杀毒软件:已安装* 域控权限:可使用net use远程登陆,不使用3389 0x02测试方法: ( ...

  6. 015.2Condiction接口

    Condiction对象能够让线程等待,也能够唤醒相应的线程,通过下面方法,具体看代码:await();signal();signalAll(); 使用步骤:1)创建锁2)通过锁拿到Condictio ...

  7. angular2 Router类中的路由跳转navigate

    navigate是Router类的一个方法,主要用来路由跳转. 函数定义 navigate(commands: any[], extras?: NavigationExtras) : Promise` ...

  8. ubuntu nginx本地局域网布署sever_name设置

    如果没有设置好sever_name 在本地输入虚拟机的ip.只会看到nginx的helloworld(打招呼界面,不可能写helloworld)界面 重点在于nginx的布署文件要加上这么一条   来 ...

  9. Ping服务

    什么是Ping服务 ping是基于XML_RPC标准协议的更新通告服务,用于博客把内容更新快速通知给百度,以便百度及时进行抓取和更新. Ping服务使用方法 你可以采取手动通知和自动通知两种方式使用p ...

  10. docker-6-DockerFile解析

    1.是什么 Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本. 构建三步骤: 1.编写Dockerfile文件 2.docker build 3.docker ...