Redis持久化及过期删除策略

Redis 持久化之RDB和AOF

RDB 详解

快照(snapshotting,RDB) RDB 是 Redis 默认的持久化方案。在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis 重启会通过加载dump.rdb文件恢复数据

从配置文件了解RDB 打开 redis.conf 文件,找到 SNAPSHOTTING 对应内容

  1. RDB核心规则配置(重点)

     save <seconds> <changes>
     #save ""
     save 900 1
     save 300 10
     save 60 10000
    

    说明:save <指定时间间隔> <执行指定次数更新操作>,满足条件就将内存中的数据同步到硬盘中。官方出厂配置默认是 900秒内有1个更改,300秒内有10个更改以及60秒内有10000个更改,则将内存中的数据快照写入磁盘。 若不想用RDB方案,可以把 save “” 的注释打开,下面三个注释。

  2. 指定本地数据库文件名,一般采用默认的 dump.rdb dbfilename dump.rdb

  3. 指定本地数据库存放目录,一般也用默认配置 dir ./

  4. 默认开启数据压缩 rdbcompression yes

    解说:配置存储至本地数据库时是否压缩数据,默认为yes。Redis采用LZF压缩方式,但占用了一点CPU的时间。若关闭该选项,但会导致数据库文件变的巨大。建议开启。

触发RDB快照

  • 在指定的时间间隔内,执行指定次数的写操作
  • 执行save(阻塞, 只管保存快照,其他的等待) 或者是bgsave (异步)命令
  • 执行flushall 命令,清空数据库所有数据,意义不大。
  • 执行shutdown 命令,保证服务器正常关闭且不丢失任何数据,意义…也不大。 注意:

save备份过程:save备份是同步的,如果备份的数据量过大的话,服务器会暂停几百毫秒甚至是1秒

bgsave备份过程:bgsave备份会单独创建一个子进程,将备份的数据写入一个临时文件

RDB数据还原 找到备份临时文件的指令是 config get dir 指令执行成功以后将备份临时文件的目录拷贝到Redis的安装目录下 然后重新启动Redis服务就成功还原数据了

通过RDB文件恢复数据 将dump.rdb 文件拷贝到redis的安装目录的bin目录下,重启redis服务即可。在实际开发中,一般会考虑到物理机硬盘损坏情况,选择备份dump.rdb 。可以从下面的操作演示中可以体会到。

RDB 的优缺点 优点:

适合大规模的数据恢复。

如果业务对数据完整性和一致性要求不高,RDB是很好的选择。

缺点:

数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。

备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍 哦),最后再将临时文件替换之前的备份文件。

所以Redis 的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的。

AOF 详解

追加文件(append-only file, AOF) AOF :Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并追加到文件中。Redis 重启的会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

从配置文件了解AOF

打开redis.conf 文件,找到 APPEND ONLY MODE 对应内容

  1. redis 默认关闭,开启需要手动把no改为yes
    appendonly yes

  2. 指定本地数据库文件名,默认值为 appendonly.aof
    appendfilename "appendonly.aof"

  3. 指定更新日志条件

     #appendfsync always
     appendfsync everysec
     #appendfsync no
    

    说明:always:同步持久化,每次发生数据变化会立刻写入到磁盘中。性能较差当数据完整性比较好(慢,安全)

    everysec:出厂默认推荐,每秒异步记录一次(默认值)

    no:不同步

  4. 配置重写触发机制

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

解说:当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。一般都设置为3G,64M太小了。

触发AOF快照

根据配置文件触发,可以是每次执行触发,可以是每秒触发,可以不同步。

根据AOF文件恢复数据

正常情况下,将appendonly.aof 文件拷贝到redis的安装目录的bin目录下,重启redis服务即可。但在实际开发中,可能因为某些原因导致appendonly.aof 文件格式异常,从而导致数据还原失败,可以通过命令redis-check-aof –fix appendonly.aof 进行修复 。从下面的操作演示中体会。

AOF的重写机制

面也说到了,AOF的工作原理是将写操作追加到文件中,文件的冗余内容会越来越多。所以聪明的 Redis 新增了重写机制。当AOF文件的大小超过所设定的阈值时,Redis就会对AOF文件的内容压缩。

重写的原理:Redis 会fork出一条新进程,读取内存中的数据,并重新写到一个临时文件中,并没有读取旧文件,最后替换旧的aof文件。

触发机制:当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。这里的“一倍”和“64M” 可以通过配置文件修改。

AOF 的优缺点

优点:数据的完整性和一致性更高

缺点:因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。

总结

  • Redis 默认开启RDB持久化方式,在指定的时间间隔内,执行指定次数的写操作,则将内存中的数据写入到磁盘中。
  • RDB 持久化适合大规模的数据恢复但它的数据一致性和完整性较差。
  • Redis 需要手动开启AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中。
  • AOF 的数据完整性比RDB高,但记录内容多了,会影响数据恢复的效率。
  • Redis 针对 AOF文件大的问题,提供重写的瘦身机制。
  • 若只打算用Redis 做缓存,可以关闭持久化。
  • 若打算使用Redis 的持久化。建议RDB和AOF都开启。其实RDB更适合做数据的备份,留一后手。AOF出问题了,还有RDB。

过期删除策略

Redis有三种不同的删除策略:

  1. 立即删除:在设置键的过期时间时,创建一个回调事件,当过期时间达到时,由时间处理器自动执行键的删除操作。

  2. 惰性删除:键过期了就过期了,不管。每次从dict字典中按key取值时,先检查此key是否已经过期,如果过期了就删除它,并返回nil,如果没过期,就返回键值。

  3. 定时删除:每隔一段时间,对expires字典进行检查,删除里面的过期键。

立即删除

立即删除能保证内存中数据的最大新鲜度,因为它保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。但是立即删除对cpu是最不友好的。因为删除操作会占用cpu的时间,如果刚好碰上了cpu很忙的时候,比如正在做交集或排序等计算的时候,就会给cpu造成额外的压力。

而且目前redis事件处理器对时间事件的处理方式–无序链表,查找一个key的时间复杂度为O(n),所以并不适合用来处理大量的时间事件。

惰性删除

惰性删除是指,某个键值过期后,此键值不会马上被删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。所以惰性删除的缺点很明显:浪费内存。dict字典和expires字典都要保存这个键值的信息。

举个例子,对于一些按时间点来更新的数据,比如log日志,过期后在很长的一段时间内可能都得不到访问,这样在这段时间内就要白白浪费这么多内存来存log。这对于性能非常依赖于内存大小的redis来说,是比较致命的。

定时删除

从上面分析来看,立即删除会短时间内占用大量cpu,惰性删除会在一段时间内浪费内存,所以定时删除是一个折中的办法。

定时删除是:每隔一段时间执行一次删除操作,并通过限制删除操作执行的时长和频率,来减少删除操作对cpu的影响。另一方面定时删除也有效的减少了因惰性删除带来的内存浪费。

redis使用的策略

redis使用的过期键值删除策略是:惰性删除加上定期删除,两者配合使用。

参考文章: Redis持久化及过期删除策略