Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
众所周知,Redis的强劲性能很大程度上是由于其将所有数据都存储在内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中以某种方式同步到硬盘中,这一过程就是持久化.Redis对于内部数据的持久化存储有两种实现策略, 一种是基于快照形式的RDB策略, 另外一种是基于磁盘的AOF策略.下面将详细介绍这两种持久化策略的工作方式以及内部实现原理.
1. RDB持久化
此种持久化策略在Redis中是默认开启的,无需用户手动开启并且自带三种触发条件. RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件(即默认的三种触发条件)时Redis会自动将内存中的所有数据进行快照并存储在硬盘上,即当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照. 但是当默认的触发条件无法满足用户需求的时候,那么就需要用户手动的去修改redis的配置文件(在名为redis.conf文件中需要修改两个参数:时间和改动的键的次数).详情请看下图:
根据上图所示, save参数指定了快照的条件,可以存在多个条件,条件之间是”或”的关系,redis默认的RDB触发策略是: 当在15分钟内有至少一个键发生改变、当在5分钟内有至少10个键发生改变、当在一分钟内至少10000个键发生改变. 如果想要禁用自动快照,只需要将所有的save参数删除即可.
Redis默认会将快照文件存储在当前目录的名为:dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名.
实现快照的过程
1) Redis使用fork函数复制一份当前进程(父进程)的副本(子进程)
2) 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入磁盘中的临时文件
3) 当子进程写完所有数据后会用当前的临时文件覆盖掉之前老的dump.rdb文件
通过上述过程我们可以轻易的发现,Redis在进行快照的过程中不会修改dump.rdb文件,只有在快照结束后才会将之前的文件替换成新的,通过这种方式可以保证在任何时候,dump.rdb文件的内容都是完整的. 基于这种实现机制,来保证定时备份dump.rdb文件来实现Redis的持久化.当读到这里你可能会想,随着redis内部数据的不断增加, 那么伴随着的就是快照文件的大小也会不断增加,那么会不会增加磁盘空间的占用率. 首先,现在市场上的物理设备的价格在不断降低,其次,快照文件是经过压缩的二进制文件,占用的空间会小于内存中的数据大小.
RDB方式也存在它自身的问题,就是通过这种方式实现redis整体持久化的话,一旦redis异常退出,那么就会丢失最后一次快照以后更改的所有数据.那么此时就需要使用者根据自己当前实际的生产场景来灵活的配置快照触发条件,尽可能地保证当发生异常时,数据损失控制在最小的范围中. 那么如果使用者严格要求数据的完整,无法承受任何风险的话,那么就可以考虑下面要说的AOF方式.
2. AOF持久化
此种方式需要使用者手动开启, 开启方式为: 更改redis.conf文件中的appendonly属性为true. 当开始以后会产生一个名为appendonly.aof持久化文件.如需修改持久化文件名称的话, 需要修改名为appendfilename属性.该种持久化策略也有三种触发条件分为别: always、everysec、no.详情请看下图:
假设在开启AOF持久化的情况下执行了如下4个命令:
SET foo 1
SET foo 2
SET foo 3
GET foo
Aof方式在持久化文件记录对redis数据的添加、修改、删除这三类命令.查询的命令不会记录.所以Redis会将前三条写入AOF文件中.此时aof文件中的内容为:
可见aof文件是纯文本文件,可见aof记录的三条对redis数据库中的数据发生改变的三条命令, 但是根据结果可以发现, 这三条命令,只有最后一条是有用的, 前两条命令本身是冗余的.因为这三条命令的key都是相同的,那么在最终执行的时候, 前两条命令其实会被第三条命令覆盖掉. 基于这个发现, 我们可以察觉到随着对Redis操作的不断增长,当开启了aof以后, 那么产生的持久化文件的体积也会随着操作数据而不断增长,即便内存中的数据本身没有多少.那么现在想要解决这个问题,该怎么办呢 ? 其实Redis本身已经给我们提供了解决的方案. 可以自动地优化AOF持久化文件. 就上例而言, 我们最终的目的是删除前两条冗余的记录,且保留第三条. 实际上Redis也是这么做的. 每当达到一定条件时Redis就会自动重写AOF文件,这个条件需要修改redis配置文件的两条属性,详情请看下图
Auto-aof-rewrite-percentage代表当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据.
Auto-aof-rewrite-min-size代表限制了允许重写的最小AOF文件的大小,通常AOF文件很小的情况下即使其中有很多冗余的命令我们也并不关心.
最后Redishi允许将RDB和AOF这两种持久化策略同时开启的,但是当两种策略同时开启了以后, 那么会以AOF产生的记录为准, 换句话说就是AOF这种持久化策略的优先级是高于RDB的.当redis在重启了以后也会使用AOF文件中的内容来恢复数据,因为相对比来说,RDB这种方式丢失数据的风险是高于AOF的.