阅读更多

13顶
0踩

数据库

转载新闻 Redis作者:深度剖析Redis持久化

2012-03-28 15:34 by 正式编辑 nemohq 评论(4) 有25837人浏览
Redis是一种面向“key-value”类型数据的分布式NoSQL数据库系统,具有高性能、持久存储、适应高并发应用场景等优势。它虽然起步较晚,但发展却十分迅速。

近日,Redis的作者在博客中写到,他看到的所有针对Redis的讨论中,对Redis持久化的误解是最大的,于是他写了一篇长文来对Redis的持久化进行了系统性的论述。文章主要包含三个方面:Redis持久化是如何工作的、这一性能是否可靠以及和其它类型的数据库比较。以下为文章内容:

一、Redis持久化是如何工作的?

什么是持久化?简单来讲就是将数据放到断电后数据不会丢失的设备中,也就是我们通常理解的硬盘上。首先我们来看一下数据库在进行写操作时到底做了哪些事,主要有下面五个过程

  • 客户端向服务端发送写操作(数据在客户端的内存中)。
  • 数据库服务端接收到写请求的数据(数据在服务端的内存中)。
  • 服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
  • 操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
  • 磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。
故障分析

写操作大致有上面5个流程,下面我们结合上面的5个流程看一下各种级别的故障

  • 当数据库系统故障时,这时候系统内核还是完好的。那么此时只要我们执行完了第3步,那么数据就是安全的,因为后续操作系统会来完成后面几步,保证数据最终会落到磁盘上。
  • 当系统断电时,这时候上面5项中提到的所有缓存都会失效,并且数据库和操作系统都会停止工作。所以只有当数据在完成第5步后,才能保证在断电后数据不丢失
通过上面5步的了解,可能我们会希望搞清下面一些问题

  • 数据库多长时间调用一次write,将数据写到内核缓冲区?
  • 内核多长时间会将系统缓冲区中的数据写到磁盘控制器?
  • 磁盘控制器又在什么时候把缓存中的数据写到物理介质上?
对于第一个问题,通常数据库层面会进行全面控制。而对第二个问题,操作系统有其默认的策略,但是我们也可以通过POSIX API提供的fsync系列命令强制操作系统将数据从内核区写到磁盘控制器上。对于第三个问题,好像数据库已经无法触及,但实际上,大多数情况下磁盘缓存是被设置关闭的,或者是只开启为读缓存,也就是说写操作不会进行缓存,直接写到磁盘。建议的做法是仅仅当你的磁盘设备有备用电池时才开启写缓存

数据损坏

所谓数据损坏,就是数据无法恢复,上面我们讲的都是如何保证数据是确实写到磁盘上去,但是写到磁盘上可能并不意味着数据不会损坏。比如我们可能一次写请求会进行两次不同的写操作,当意外发生时,可能会导致一次写操作安全完成,但是另一次还没有进行。如果数据库的数据文件结构组织不合理,可能就会导致数据完全不能恢复的状况出现。

这里通常也有三种策略来组织数据,以防止数据文件损坏到无法恢复的情况

  • 第一种是最粗糙的处理,就是不通过数据的组织形式保证数据的可恢复性。而是通过配置数据同步备份的方式,在数据文件损坏后通过数据备份来进行恢复。实际上MongoDB在不开启操作日志,通过配置Replica Sets时就是这种情况。
  • 另一种是在上面基础上添加一个操作日志,每次操作时记一下操作的行为,这样我们可以通过操作日志来进行数据恢复。因为操作日志是顺序追加的方式写的,所以不会出现操作日志也无法恢复的情况。这也类似于MongoDB开启了操作日志的情况。
  • 更保险的做法是数据库不进行旧数据的修改,只是以追加方式去完成写操作,这样数据本身就是一份日志,这样就永远不会出现数据无法恢复的情况了。实际上CouchDB就是此做法的优秀范例。
1、Redis的第一个持久化策略:RDB快照

Redis支持将当前数据的快照存成一个数据文件的持久化机制。而一个持续写入的数据库如何生成快照呢。Redis借助了fork命令的copy on write机制。在生成快照时,将当前进程fork出一个子进程,然后在子进程中循环所有的数据,将数据写成为RDB文件。

我们可以通过Redis的save指令来配置RDB快照生成的时机,比如你可以配置当10分钟以内有100次写入就生成快照,也可以配置当1小时内有1000次写入就生成快照,也可以多个规则一起实施。这些规则的定义就在Redis的配置文件中,你也可以通过Redis的CONFIG SET命令在Redis运行时设置规则,不需要重启Redis。

Redis的RDB文件不会坏掉,因为其写操作是在一个新进程中进行的,当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件,这样在任何时候出现故障,Redis的RDB文件都总是可用的。

同时,Redis的RDB文件也是Redis主从同步内部实现中的一环。

但是,我们可以很明显的看到,RDB有它的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到 Redis停机这段时间的数据全部丢掉了。在某些业务下,这是可以忍受的,我们也推荐这些业务使用RDB的方式进行持久化,因为开启RDB的代价并不高。 但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,RDB就无能为力了,所以Redis引入了另一个重要的持久化机制:AOF日志。

2、Redis的第二个持久化策略:AOF日志

AOF日志的全称是Append Only File,从名字上我们就能看出来,它是一个追加写入的日志文件。与一般数据库不同的是,AOF文件是可识别的纯文本,它的内容就是一个个的Redis标准命令。比如我们进行如下实验,使用Redis2.6 版本,在启动命令参数中设置开启AOF功能:

./redis-server --appendonly yes

然后我们执行如下的命令:

redis 127.0.0.1:6379> set key1 Hello
OK
redis 127.0.0.1:6379> append key1 " World!"
(integer) 12
redis 127.0.0.1:6379> del key1
(integer) 1
redis 127.0.0.1:6379> del non_existing_key
(integer) 0

这时我们查看AOF日志文件,就会得到如下内容:

$ cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$4
key1
$5
Hello
*3
$6
append
$4
key1
$7
 World!
*2
$3
del
$4
key1

可以看到,写操作都生成了一条相应的命令作为日志。其中值得注意的是最后一个del命令,它并没有被记录在AOF日志中,这是因为Redis判断出 这个命令不会对当前数据集做出修改。所以不需要记录这个无用的写命令。另外AOF日志也不是完全按客户端的请求来生成日志的,比如命令 INCRBYFLOAT 在记AOF日志时就被记成一条SET记录,因为浮点数操作可能在不同的系统上会不同,所以为了避免同一份日志在不同的系统上生成不同的数据集,所以这里只将操作后的结果通过SET来记录。

AOF重写

你可以会想,每一条写命令都生成一条日志,那么AOF文件是不是会很大?答案是肯定的,AOF文件会越来越大,所以Redis又提供了一个功能,叫做AOF rewrite。其功能就是重新生成一份AOF文件,新的AOF文件中一条记录的操作只会有一次,而不像一份老文件那样,可能记录了对同一个值的多次操作。其生成过程和RDB类似,也是fork一个进程,直接遍历数据,写入新的AOF临时文件。在写入新文件的过程中,所有的写操作日志还是会写到原来老的 AOF文件中,同时还会记录在内存缓冲区中。当重完操作完成后,会将所有缓冲区中的日志一次性写入到临时文件中。然后调用原子性的rename命令用新的 AOF文件取代老的AOF文件。

二、Redis持久化性能是否可靠?

从上面的流程我们能够看到,RDB是顺序IO操作,性能很高。而同时在通过RDB文件进行数据库恢复的时候,也是顺序的读取数据加载到内存中。所以也不会造成磁盘的随机读取错误。

而AOF是一个写文件操作,其目的是将操作日志写到磁盘上,所以它也同样会遇到我们上面说的写操作的5个流程。那么写AOF的操作安全性又有多高呢?实际上这是可以设置的,在Redis中对AOF调用write写入后,何时再调用fsync将其写到磁盘上,通过appendfsync选项来控制,下面appendfsync的三个设置项,安全强度逐渐变强。

1、appendfsync no

当设置appendfsync为no的时候,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上

2、appendfsync everysec

当设置appendfsync为everysec的时候,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一 次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞。

所以,结论就是:在绝大多数情况下,Redis会每隔一秒进行一次fsync。在最坏的情况下,两秒钟会进行一次fsync操作

这一操作在大多数数据库系统中被称为group commit,就是组合多次写操作的数据,一次性将日志写到磁盘。

3、appednfsync always

当设置appendfsync为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到影响。

对于pipelining有什么不同?

对于pipelining的操作,其具体过程是客户端一次性发送N个命令,然后等待这N个命令的返回结果被一起返回。通过采用pipilining 就意味着放弃了对每一个命令的返回值确认。由于在这种情况下,N个命令是在同一个执行过程中执行的。所以当设置appendfsync为everysec 时,可能会有一些偏差,因为这N个命令可能执行时间超过1秒甚至2秒。但是可以保证的是,最长时间不会超过这N个命令的执行时间和。

三、和其它数据库的比较

上面操作系统层面的数据安全我们已经讲了很多,其实,不同的数据库在实现上都大同小异。总之,最后的结论就是,在Redis开启AOF的情况下,其单机数据安全性并不比这些成熟的SQL数据库弱

在数据导入方面的比较

这些持久化的数据有什么用,当然是用于重启后的数据恢复。Redis是一个内存数据库,无论是RDB还是AOF,都只是其保证数据恢复的措施。所以 Redis在利用RDB和AOF进行恢复的时候,都会读取RDB或AOF文件,重新加载到内存中。相对于MySQL等数据库的启动时间来说,会长很多,因为MySQL本来是不需要将数据加载到内存中的。

但是相对来说,MySQL启动后提供服务时,其被访问的热数据也会慢慢加载到内存中,通常我们称之为预热,而在预热完成前,其性能都不会太高。而Redis的好处是一次性将数据加载到内存中,一次性预热。这样只要Redis启动完成,那么其提供服务的速度都是非常快的。

而在利用RDB和利用AOF启动上,其启动时间有一些差别。RDB的启动时间会更短,原因有两个,一是RDB文件中每一条数据只有一条记录,不会像 AOF日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。另一个原因是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不需要再进行数据编码工作。在CPU消耗上要远小于AOF日志的加载。

英文原文:Redis persistence demystified
来自: NoSQLFan
13
0
评论 共 4 条 请登录后发表评论
4 楼 attentionyiun 2014-12-11 17:05
3 楼 lv双 2014-11-12 14:00
问:如果使用RDB快照持久化策略,第一次持久化没有处理完就要进行第二次持久化的话是如何处理的呢?
2 楼 lvren007 2014-08-28 18:00
1 楼 caizi12 2014-06-17 13:44

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • Redis:Redis配置文件相关配置、Redis的持久化

    目录:(1)Redis的配置文件(2)常规配置(3)安全配置(4)Redis的持久化策略RDB(5)Redis的持久化策略AOF (6)Redis的持久化 (1)Redis的配置文件当修改配置文件后,在启动Redis的时候需要,加上配置文件的...

  • Redis系列:Redis持久化机制与Redis事务

    Redis 是个基于内存的数据库。那服务一旦宕机,内存中数据必将全部丢失。所以丢失数据的恢复对于 Redis 是十分重要的,我们首先想到是...因此实现数据的持久化,避免从后端数据库中恢复数据,对于Redis 是十分必要的。

  • Redis持久化方案

    持久化方式 通常数据库存在三种用于持久操作以防止数据损坏的常见策略: 1.是数据库不关心故障,而是在数据文件损坏后从数据备份或快照中恢复。RDB就是这种情况 2.该数据库使用操作日志记录每个操作的操作行为,以...

  • Redis持久化:RDB和AOF

    Redis对数据的操作都是基于内存的,当遇到了进程退出、服务器宕机等意外情况,如果没有持久化机制,那么Redis中的数据将会丢失无法恢复。有了持久化机制,Redis在下次重启时可以利用之前持久化的文件进行数据恢复。...

  • Redis的持久化详解

    Redis的持久化,Redis是一个基于内存的数据库,它的数据是存放在内存中,内存有个问题就是关闭服务或者断电会丢失。Redis的数据也支持写到硬盘中,这个过程就叫做持久化。RDB(Redis DataBase):简而言之,就是在...

  • Redis持久化

    redis

  • 一篇文章彻底理解Redis持久化:RDB和AOF

    理解和掌握Redis的持久机制,对于Redis的日常开发和运维都有很大帮助,也是在大厂面试经常被问到的知识点。

  • 面试:redis的两种持久化方式

    面试:redis的两种持久化方式 RDB 根据一段时间内操作key的数量进行一次rdb快照保存 确点:快照是定期生成的,可能会丢失一部分数据 AOF 以日志的方式记录每次写命令,重启时重新执行aof中的命令,达到恢复数据的...

  • 【Redis持久化】:Redis持久化的意义

    【Redis持久化】:Redis持久化的意义 1. Redis持久化的意义 Redis作为分布式缓存架构中重要的一环,用于保存一些较为重要的数据,抗住系统的高并发访问。因此Redis中的数据必须持久化,防止服务或系统宕机导致数据...

  • redis 02:Redis的持久化

    一、redis的持久化机制 就是在指定的时间间隔内,将内存当中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存 什么意思呢?我们都知道,内存当中的数据,如果我们一断电,那么数据必然会丢失,但是玩过...

  • Redis数据持久化

    通过本篇博文学习Redis的持久化操作!

  • Redis(一):Redis的持久化的原理和操作

    目录 写在前面 1、电商架构方案 1.1、页面静态化 2、大型网站 3、缓存架构 3、redis持久化对容灾意义 3.1、redis持久化意义 4、RDB和AOF 4.1、RDB和AOF两种持久化机制的介绍 4.2、RDB持久化机制的优点 4.3、RDB持久...

  • 【Redis】Redis持久化之RDB详解(Redis专栏启动)

    本文讲解Redis持久性机制RDB,RDB持久化的两种方法(RDB的两种策略方式、save和bgsave命令)并进行比较,如何使用RDB策略备份数据,分析Redis RDB优缺点,bgsave原理,bgsave执行流程,fork的实现原理(Copy On ...

  • redis持久化

    Redis官方提供了两种持久化的方式,分别是: 快照(snapshot):保存某一时刻redis中的所有数据状态,需要时恢复快照即可回到快照的状态 AOF(Append Only File)追加日志文件:将所有redis的写命令记录到日志文件中,...

  • redis的持久化

    一、redis持久化----两种方式 1、redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。 2、RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;...

  • redis持久化配置

    redis有两种持久化方式:RDB和AOF。 RDB配置方式 默认情况下,是快照RDB的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是dump.rdb redis.conf默认配置: save 900 1 save 300 10 save ...

  • redis混合持久化

    RDB 和 AOF 持久化各有利弊,RDB 可能会导致一定时间内的数据丢失,而 AOF 由于文件较大则会影响 Redis 的启动速度,为了能同时使用 RDB 和 AOF 各种的优点,Redis 4.0 之后新增了混合持久化的方式。在开启混合持久...

  • Redis持久化:RDB、AOF

    它与memcached类似,不过Redis支持数据的持久化,而且支持的数据类型非常的丰富,如:string(字符串),list(列表),set(集合),sorted set(有序集合),hash(哈希)。除了支持丰富的数据类型之外,还能够在服务器端...

  • Redis7持久化

    Redis7持久化-->RDB和AOP

  • 基于Qt开发的截图工具- 支持全屏截图, 支持自定义截图,支持捕获窗口截图,支持固定大小窗口截图,颜色拾取,图片编辑

    基于Qt开发的截图工具.zip 截图工具(QScreenShot) Qt编写的一款截图工具。 特点 - 支持全屏截图 - 支持自定义截图 - 支持捕获窗口截图 - 支持固定大小窗口截图 - 颜色拾取 - 图片编辑 - 图片上传到wordpress 环境 Qt6.2 QtCreate 8

Global site tag (gtag.js) - Google Analytics