Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富。有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交和补集(difference)等,还支持多种排序功能。所以Redis也可以被看成是一个数据结构服务 器。
Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。

 

第一种方法filesnapshotting(快照):这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置:

save 900 1  #900秒内如果超过1个key被修改,则发起快照保存
 save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
 save 60 10000

save N M表示在N秒之内,redis至少发生M次修改则redis抓快照到磁盘。当然我们也可以手动执行save或者bgsave(异步)做快照。

工作原理简单介绍一下:当redis需要做持久化时,redis会fork一个子进程;子进程将数据写到磁盘上一个临时RDB文件中;当子进程完成写临时文件后,将原来的RDB替换掉,这样的好处就是可以copy-on-write

filesnapshotting方法在redis异常死掉时, 最近的数据会丢失(丢失数据的多少视你save策略的配置),所以这是它最大的缺点,当业务量很大时,丢失的数据是很多的

(二)Append-only file

  aof 比快照方式有更好的持久化性,是由于在使用aof持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中(默认是appendonly.aof)。当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。当然由于os会在内核中缓存 write做的修改,所以可能不是立即写到磁盘上。这样aof方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉redis我们想要通过fsync函数强制os写入到磁盘的时机。有三种方式如下(默认是:每秒fsync一次):

appendonly yes           #启用aof持久化方式
 # appendfsync always   #每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
 appendfsync everysec     #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
 # appendfsync no    #完全依赖os,性能最好,持久化没保证

aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件。redis提供了bgrewriteaof命令 。为此,Redis 提供auto-aof-rewrite-percentageauto-aof-rewrite-min-size两个配置选项来对 AOF 重写进行配置。auto-aof-rewrite-percentageauto-aof-rewrite-min-size两个配置选项的含义可以参考 redis.conf 配置中的详细说明,具体来说,auto-aof-rewrite-percentage配置当 AOF 文件需要比旧 AOF 文件增大多少时才进行 AOF 重写,而auto-aof-rewrite-min-size则配置当 AOF 文件需要达到多大体积时才进行 AOF 重写。只有这两个配置的条件都达到时,才会进行 AOF 重写。

      auto-aof-rewrite-percentage 100
      auto-aof-rewrite-min-size 64mb

       收到此命令redis将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件。具体过程如下:
       1.  redis调用fork ,现在有父子两个进程
       2. 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
       3. 父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
       4. 当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
       5. 现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。

       需要注意到是重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。