解密Redis持久化【翻译】

本文来自Redis的作者,他在论坛看到大家对Redis持久化误解较大,所以写此文章论述持久化

写操作的流程

首先我们来看一下数据库在进行写操作时到底做了哪些事,主要有下面五个过程。

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

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

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

通过上面5步的了解,可能我们会希望搞清下面一些问题:

  • 数据库多长时间调用一次write(2),将数据写到内核缓冲区
  • 内核多长时间会将系统缓冲区中的数据写到磁盘控制器
  • 磁盘控制器又在什么时候把缓存中的数据写到物理介质上

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

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

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

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

RDB快照

下面我们说一下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 日志。

AOF日志

aof日志的全称是append only file,从名字上我们就能看出来,它是一个追加写入的日志文件。与一般数据库的binlog不同的是,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文件。

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

AOF可靠性设置

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

appendfsync no

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

appendfsync everysec

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

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

appednfsync always

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

对于pipelining有什么不同

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

与postgreSQL和MySQL的比较

这一块就不多说了,由于上面操作系统层面的数据安全已经讲了很多,所以其实不同的数据库在实现上都大同小异。 总之最后的结论就是,在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日志的加载。

原文地址:https://www.cnblogs.com/supperhan/p/11456885.html

时间: 2024-10-21 02:51:42

解密Redis持久化【翻译】的相关文章

解密Redis持久化

本文内容来源于 Redis 作者博文,Redis 作者说,他看到的所有针对 Redis 的讨论中,对 Redis持久化的误解是最大的,于是他写了一篇长文来对 Redis 的持久化进行了系统性的论述.文章非常长,也很值得一看,NoSQLFan 将主要内容简述成本文. 什么是持久化,简单来讲就是将数据放到断电后数据不会丢失的设备中.也就是我们通常理解的硬盘上. 写操作的流程 首先我们来看一下数据库在进行写操作时到底做了哪些事,主要有下面五个过程. 客户端向服务端发送写操作(数据在客户端的内存中) 数

Redis持久化机制

[RDB与AOF两种持久化模式的对比,实现原理] [RDB模式] fork一个进程,遍历hash table,利用copy on write,把整个db dump保存下来. save, shutdown, slave 命令会触发这个操作. 粒度比较大,如果save, shutdown, slave 之前crash了,则中间的操作没办法恢复. [AOF模式] 把写操作指令,持续的写到一个类似日志文件里.(类似于从postgresql等数据库导出sql一样,只记录写操作) 粒度较小,crash之后,

redis 持久化与备份策略

持久化(persistence) 本文是 Redis 持久化文档 的中文翻译. 这篇文章提供了 Redis 持久化的技术性描述,推荐所有 Redis 用户阅读. 要更广泛地了解 Redis 持久化,以及这种持久化所保证的耐久性(durability),请参考文章 Redis persistence demystified (中文). Redis 持久化 Redis 提供了多种不同级别的持久化方式: RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snaps

Redis持久化

Redis持久化功能简介: Redis为了内部数据的安全考虑,会把本身的数据以文件形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)的里边. 数据保存到硬盘的过程就称为“持久化”效果. Redis持久化的两种方式:snap shotting  快照持久化  /  append only file   AOF持久化 snap shotting快照持久化 该持久化默认开启,一次性把redis中全部的数据保存一份存储在硬盘中,如果数据非常多(10-20G)就不适合频繁进行

Redis持久化以及其原理

一.Redis持久化 Redis之所以强大是因为其将所有数据都直接存储在内存中.可是,为了使Redis在重启后数据仍然不丢失,就需要把数据以某种方式持久化到磁盘中(这是使用它作系统缓存的一大优势).Redis支持两种方式进行持久化,一种是RDB,一种是AOF,可以使用一种方式,也可以混合使用它们两种方式. 二.RDB方式(默认的持久化方式) 2.1 RDBa方式简介 其实是通过snapshot快照的方式进行持久化的,当符合一定条件时,Redis会自动将内存中的所有数据快照存储到磁盘中.进行快照的

Redis持久化实践及灾难恢复模拟

参考资料: Redis Persistence http://redis.io/topics/persistence Google Groups https://groups.google.com/forum/?fromgroups=#!forum/redis-db 一.对Redis持久化的探讨与理解 目前Redis持久化的方式有两种: RDB 和 AOF 首先,我们应该明确持久化的数据有什么用,答案是用于重启后的数据恢复. Redis是一个内存数据库,无论是RDB还是AOF,都只是其保证数据恢

redis持久化与可用性

redis对于持久化有快照及aof日志文件两种形式. 快照db文件,优点是二进制,大小比aof日志文件小.但会丢失最后一次成功备份时间到down机时间的数据. aof相比而言文件大小就大了点,但相对快照来讲,不大容易丢失文件. 目前redis检查数据文件是否有错对于快照及aof都能够支持,但修复则只对aof文件有效. 快照文件每次备份都是全量备份,原理是先fork出一个子进程,父子进程共享数据域.接着子进程开始将共享数据域中的数据写入到一个临时文件,写完之后原子性的替换掉原先的备份db文件.如果

redis持久化策略梳理及主从环境下的策略调整记录

redis是一个内存数据库,它的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为"半持久化模式"):也可以把每一次数据变化都写入到一个Append Only File(AOF)里面(这称为"完全持久化模式").redis提供了两种不同级别的持久化方式:一种是默认的RDB(filesnapshotting快照)持久化,一种是AOF持久化,这两种持久化方式都可以将内存中的数据库状态保存到磁盘上,但是原理非常不同,区别很明显! 1.RDB持久化可以在

深度剖析Redis持久化

详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt118 Redis是一种面向"key-value"类型数据的分布式NoSQL数据库系统,具有高性能.持久存储.适应高并发应用场景等优势.它虽然起步较晚,但发展却十分迅速. 近日,Redis的作者在博客中写到,他看到的所有针对Redis的讨论中,对Redis持久化的误解是最大的,于是他写了一篇长文来对Redis的持久化进行了系统性的论述.文章主要包含三个方面:Redi