redis类似于memcached,都是内存数据库,但是redis支持数据持久化,也就是说redis可以将内存中的数据同步到磁盘进行持久化,保证数据redis的安全性。不过持久化部分可能更容易让人产生误解,下面就来说说这部分。Redis持久化是如何工作的?什么是坚持?简单的说就是把数据放在一个断电后不会丢失数据的设备中,也就是我们通常所理解的硬盘。1.数据库写操作的五个过程首先我们看一下数据库在写操作的时候做了什么。主要有以下五个过程:客户端向服务器发送写操作(数据在客户端的内存中)。数据库服务器收到写请求的数据(数据在服务器的内存中)。服务器调用write系统调用将数据写入磁盘(数据在系统内存的buffer中)。操作系统将缓冲区中的数据传输到磁盘控制器(数据在磁盘缓存中)。磁盘控制器将数据写入磁盘的物理介质(数据实际落在磁盘上)。2、故障分析写操作一般有以上五个过程。当数据库系统出现故障时,此时系统内核仍然完好无损。所以这个时候只要我们完成了第三步,数据就是安全的,因为后续的操作系统会完成接下来的几步,保证数据最终落到磁盘上。当系统断电时,此时上述5项缓存全部失效,数据库和操作系统停止工作。所以,只有在第5步数据完成后,才能保证掉电后数据不丢失。【补充】这里可能有几个问题:数据库调用write多久写入一次内核缓冲区?内核多久将系统缓冲区中的数据写入磁盘控制器一次?磁盘控制器在哪里?缓存中的数据什么时候写入物理介质?对于第一个问题,通常数据库级别将拥有完全控制权。至于第二个问题,操作系统有它的默认策略,但我们也可以通过POSIXAPI提供的fsync系列命令强制操作系统将数据从内核区写入磁盘控制器。对于第三个问题,貌似数据库是够不着的,但其实大部分情况下磁盘缓存是设置为关闭的,或者只是作为读缓存开启的,也就是写操作不会缓存并直接写入磁盘。推荐的做法是仅当您的磁盘设备有备用电池时才启用写缓存。3、数据损坏所谓数据损坏,就是数据无法恢复。我们已经讲了如何保证数据确实写入了磁盘,但是写入磁盘并不代表数据不会损坏。例如,我们可能会针对一个写请求执行两种不同的写操作。当发生意外时,可能会导致一个写操作安全完成,而另一个尚未执行。如果数据库的数据文件结构组织不合理,可能会导致数据根本无法恢复的情况。解决方案三:最粗暴的处理是不通过数据的组织形式来保证数据的可恢复性。而是通过配置数据同步备份,在数据文件损坏后,可以通过数据备份来恢复。其实MongoDB在没有开启操作日志和配置ReplicaSets的情况下就是这样的。在上面的基础上增加一个操作日志,记录每次操作的行为,这样我们就可以通过操作日志进行数据恢复。因为操作日志是顺序写入的,所以不会出现操作日志无法恢复的情况。这也类似于MongoDB开启了操作日志的情况。比较安全的方式是数据库不修改旧数据,只是通过追加的方式完成写操作,这样数据本身就是一个日志,这样就永远不会出现数据无法恢复的情况。事实上,CouchDB是这种方法的一个很好的例子。那么,redis为持久化提供了哪些方法呢?Redis持久化的两种方式Redis提供了两种持久化方式,分别是RDB(RedisDataBase)和AOF(AppendOnlyFile)。RDB,简单来说就是将存储的数据快照存储在磁盘上,而AOF则是记录redis执行的所有写指令,通过write函数追加到AOF文件的末尾。下次redis重启时,只要从前到后反复执行这些写指令,就可以实现数据恢复。RDB机制1.概念RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。它也是默认的持久化方法。该方法是将内存中的数据作为快照写入二进制文件。默认文件名为dump.rdb。您可以通过配置设置来配置自动持久化快照的方式。我们可以配置redis在n秒内修改超过m个key时自动快照。以下是默认的快照保存配置。如果修改超过10个key,则启动快照保存save60100002。RDB文件保存过程中,redis调用fork,现在有子进程和父进程。父进程继续处理客户端请求,子进程负责将内存内容写入临时文件。由于os的写时复制机制(copyonwrite),父子进程会共享同一个物理页。当父进程处理写请求时,os会创建父进程要修改的页面的副本,而不是写入共享页面。因此,子进程地址空间中的数据是整个数据库在fork时刻的一个快照。子进程将快照写入临时文件后,将原来的快照文件替换为临时文件,然后子进程退出。客户端也可以使用save或者bgsave命令通知redis做快照持久化。保存操作在主线程中保存快照。由于redis使用一个主线程来处理所有的客户端请求,这种方式会阻塞所有的客户端请求。所以不推荐使用。还有一点需要注意的是,每一次持久化快照,都是将内存数据完全写入磁盘一次,只有脏数据不会增量同步。如果数据量大,写操作多,势必造成大量的磁盘io操作,可能会严重影响性能。3.优点一旦采用这种方式,你的整个Redis数据库将只包含一个文件,备份起来非常方便。例如,您可能计划每1天归档一些数据。为了方便备份,我们可以很方便地将RDB文件一个一个地移动到其他存储介质上。RDB在恢复大数据集时比AOF更快。RDB可以最大化Redis的性能:父进程在保存RDB文件时唯一需要做的就是fork一个子进程,然后子进程会处理所有后续的保存工作,父进程不需要执行任何磁盘I/OO操作。4.缺点如果你需要尽量避免服务器故障时数据丢失,那么RDB不适合你。虽然Redis允许你设置不同的保存点来控制保存RDB文件的频率,但这并不是一个容易的操作,因为RDB文件需要保存整个数据集的状态。因此,保存RDB文件可能至少需要5分钟。在这种情况下,如果发生中断,可能会丢失几分钟的数据。每次保存RDB时,Redis都必须fork()一个子进程,由子进程来做实际的持久化工作。当数据集比较大时,fork()可能会非常耗时,导致服务端在一定毫秒内停止处理客户端;如果数据集很大,CPU时间很紧,那么这个停止时间甚至可能会长一整秒。虽然AOF改写也需要fork(),但是无论AOF改写的执行间隔有多长,都不会损失数据的持久性。AOF1。概念redis会通过write函数(默认是appendonly.aof)将每一个接收到的写命令追加到文件中。当redis重启时,会通过重新执行保存在文件中的写命令,将整个数据库的内容重新构建到内存中。当然,由于os会将write所做的修改缓存在内核中,不一定会立即写入磁盘。这样aof方法的持久化可能还是会丢失一些修改。可以通过配置文件的fsync函数告诉redis强制os写入磁盘。有如下三种方式(默认:每秒fsync一次)appendonlyyes//启用aof持久化方式#appendfsyncalways//每次收到写命令时强制写入磁盘,最慢,但保证完全持久化,不推荐useappendfsynceverysec//每秒强制写入一次磁盘,这是性能和持久性之间的一个很好的折衷。推荐#appendfsyncno//完全依赖os,性能最好,不保证持久化2.AOF文件aof进程的保存方式也带来了另外一个问题。持久化文件会越来越大。例如,如果我们调用incr测试命令100次,则必须将所有100条命令保存在文件中,但其中99条是多余的。因为要恢复数据库的状态,在文件中保存一个settest100就可以了。为了压缩aof的持久化文件。Redis提供了bgrewriteaof命令。redis收到这个命令后,会用一种类似于快照的方法,将内存中的数据作为命令保存到一个临时文件中,最后替换掉原来的文件。具体过程如下:redis调用fork,现在有父子两个进程。子进程根据内存中的数据库快照,将重建数据库状态的命令写入临时文件。父进程继续处理客户端请求,除了写命令到原来的aof文件。同时缓存接收到的写命令。这样可以保证如果子进程rewrite失败,不会有问题。子进程以命令方式将快照内容写入临时文件后,子进程向父进程发送信号。然后父进程也将缓存的写命令写入临时文件。现在父进程可以用临时文件替换旧的aof文件并重命名,后面收到的写命令也会开始追加到新的aof文件中。需要注意的是,重写aof文件的操作并不是读取旧的aof文件,而是通过命令将整个内存数据库内容重写到一个新的aof文件中,有点类似于快照。3.优点使用AOF持久化会让Redis非常持久:可以设置不同的fsync策略,比如不fsync,每秒fsync一次,或者每次写命令执行fsync。AOF的默认策略是每秒fsync一次。在这种配置下,Redis依然可以保持良好的性能,即使出现故障,最多也只会丢失一秒的数据(fsync会在后台线程中执行,所以主线程可以继续努力处理命令请求).AOF文件是一个只做append操作的日志文件,所以不需要seek写入AOF文件,即使由于某些原因日志中包含不完整的命令(比如写入时磁盘已满,中途写入宕机等),redis-check-aof工具也可以轻松修复此类问题。Redis可以在AOF文件过大时在后台自动重写AOF:重写后的新AOF文件包含恢复当前数据集所需的最小命令集。整个重写操作是绝对安全的,因为Redis在创建新AOF文件的过程中,会不断向已有的AOF文件追加命令。即使在重写过程中发生关机,现有的AOF文件也不会丢失。.一旦创建了新的AOF文件,Redis将从旧的AOF文件切换到新的AOF文件,并开始追加到新的AOF文件。AOF文件有序的保存了所有对数据库的写操作。这些写操作都是以Redis协议的格式保存的,所以AOF文件的内容很容易让人看懂,也很容易分析文件(parse)。导出AOF文件也很简单:比如不小心执行了FLUSHALL命令,但是只要AOF文件没有被覆盖,那么只要停止服务器,去掉AOF文件末尾的FLUSHALL命令,即可重启Redis,数据集可以恢复到FLUSHALL执行前的状态。4.缺点对于相同的数据集,AOF文件的体积通常比RDB文件的体积要大。根据使用的fsync策略,AOF可能比RDB慢。总的来说每秒fsync的性能还是很高的,关闭fsync可以让AOF和RDB一样快,即使是在高负载下。但是,在处理巨大的写入负载时,RDB可以提供更有保障的最大延迟。小结我们应该选择RDB还是AOF,要看具体的应用场景。官方建议是两者同时使用。这提供了更可靠的持久化解决方案。其实RDB和AOF方式也可以同时使用。这种情况下,如果重启redis,会优先使用AOF方式进行数据恢复,因为AOF方式的数据恢复更完整。如果不需要数据持久化,也可以关闭RDB和AOF方式。这样一来,redis就会变成一个纯内存数据库,就像memcache一样。
