Redis内存回收和持久化策略

本文介绍了Redis的内存管理机制,包括key过期策略、内存淘汰策略及其配置,以及Redis的两种持久化方式:RDB快照和AOF日志,涵盖了各自的优缺点和适用场景。
概述

Redis所有数据都存在内存中,在某些时候需要对占用的内存空间进行回收,内存回收主要分为两类,一类是key过期,一类是内存使用达到上限,触发内存淘汰。

Key过期策略

要实现key过期,有几种思路:

定时淘汰(主动淘汰)

每个设置了过期时间的key都会设置一个定时器,定时时间为key的过期时间,然后key过期了,定时器也正好触发,就会立即清除过期的那个key,该策略可以立即清除过期的数据,对内存很友好,但是因为创建了大量定时器,会占用大量的CPU,从而影响缓存的响应时间和吞吐量。

惰性淘汰

只有当访问一个key时,才会判断key是否过期,过期就清除,该策略可以最大化节省cpu资源,但是对内存很不友好,key不访问就算过期了也得不到清除,极端情况下大量过期key得不到访问从而导致大量过期key得不到清除。

定期淘汰

每隔一定的时间(定期),会扫描一定数量的数据库的 expires 字典中一定数量的 key,并清除其中已过期的 key(不是全部扫描全部清除,而是扫描一部分,并清除其中的过期key)。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得 CPU 和内存资源达到最优的平衡效果。

expires 字典是记录了设置了过期时间的key的指针。

Redis默认开启了定期淘汰和惰性淘汰策略,这两个策略相互配合可以很好的解决过期key的处理,一般不要开启定时淘汰策略。

淘汰策略

如果清理了过期key,但是内存还是满了,就要使用内存的淘汰算法来决定清理哪些数据。

redis服务器的内存配置redis.conf:

maxmemory <bytes>    #配置redis能使用的最大内存,单位byte,如果不设置,64 位系统不限制内存,32 位系统最多使用 3GB 内存。

redis5.0有8种内存淘汰策略:

淘汰策略解释
volatile-lru根据LRU(最近最少使用)算法来删除设置了过期时间的key(只针对设置了过期时间的key,持久化key不会被淘汰),直到腾出足够内存为止,如果没有可以删除的key,也就是删除完了能删除的所有key后,还没有腾出足够内存的话,就会回退到noeviction策略
allkeys-lru跟上面的淘汰算法一样,只是他针对的是所有key,会一直删除key,直到腾出足够内存
volatile-lfu淘汰访问频率最少的key,redis内部会对每个key维护一段时间内的访问(频率) ,这里只针对设置了过期时间的key
allkeys-lfu跟上面的淘汰算法一样,只是他针对的是所有key,会一直删除key,直到腾出足够内存
volatile-random使用随机算法,在设置了过期时间的key集合中随机淘汰key
allkeys-random使用随机算法,针对所有key,会一直删除key,直到腾出足够内存
volatile-ttl删除离过期时间最近的key,也就是删除最快过期的key,直到腾出足够内存,如果没有, 回退到 noeviction 策略
noeviction默认策略, 不会删除任何数据, 拒绝所有写入操作并返回客户端错误信息(error) OOM command not allowed when used memory, 此时 Redis 只响应读操作。

如果没有符合前提条件的 key 被淘汰,那么 volatile-lru、volatile-lfu、volatile-random 、volatile-ttl 相当于 noeviction(不做内存回收)。

在配置文件中通过maxmemory-policy volatile-lru 设置指定的淘汰策略,建议使用 volatile-lru,在保证正常服务的情况下,优先删除最近最少使用的 key。

频率是是用基于概率的对数计数器实现的。
关于LFU算法的两个配置:
lfu-log-factor 10 这个是设置频率增长的速率,设置的值越大,频率增长的越慢。
lfu-decay-time 1 这个是设置频率衰减的,如果设置为1,那么就是一分钟没有被访问,就衰减1。

持久化

Redis 速度快,很大一部分原因是因为它所有的数据都存储在内存中。如果断电或者宕机,都会导致内存中的数据丢失。为了实现重启后数据不丢失,Redis 提供了两种持久化的方案,一种是 RDB 快照(Redis DataBase),一种是 AOF(Append Only File)。

持久化只会持久化没有设置过期时间的key,设置了过期时间的key会自动忽略。

RDB

RDB 是 Redis 默认的持久化方案。当满足一定条件的时候,会把当前内存中的数据写入磁盘,生成一个快照文件 dump.rdb。Redis 重启会通过加载 dump.rdb 文件恢复数据。

触发条件:
自动触发:
通过配置redis.conf文件来设置自动触发RDB的规则,其中定义了触发把数据保存到磁盘的触发频率。
如果不需要 RDB 方案,注释 save 或者配置成空字符串""。

#默认如下三个规则,如果符合下面的任意规则,redis服务就会进行一个数据快照。
save 900 1   #900秒内对至少一个key进行修改、添加、删除等事务操作。
save 300 10  #300秒内对至少10个key进行修改、添加、删除等事务操作。
save 60 10000 #60秒内对至少10000个key进行修改、添加、删除等事务操作。


dir 文件目录  #设置生成的RDB文件存放的目录。默认在启动目录下(相对路径),同时启动redis服务器恢复数据时也是使用该目录下的RDB文件。
dbfilename 文件名  #生成的RDB文件的文件名。同时也是用于恢复数据的RDB文件。
rdbcompression yes  #是否对生成的RDB文件进行压缩,开启压缩可以节省存储空间, 但是会消耗一些 CPU 的计算时间, 默认开启
rdbchecksum yes  #使用 CRC64 算法来进行数据校验, 但是这样做会增加大约 10%的性能消耗, 如果希望获取到最大的性能提升, 可以关闭此功能。

shutdown 触发,保证服务器正常关闭,在服务器正常关闭的时候会触发一次快照。
flushall 命令会触发,但是生成的RDB 文件是空的,没什么意义(删掉 dump.rdb 演示一下)。

手动触发:
可以手动触发RDB快照,为了迁移数据,备份数据,或者定时RDB保证数据尽可能少丢失等原因时,需要手动触发RDB快照。

a)save命令
save 在生成快照的时候会阻塞当前 Redis 服务器, Redis 不能处理其他命令。如果内存中的数据比较多,会造成 Redis 长时间的阻塞。生产环境不建议使用这个命令。

b)bgsave命令
执行 bgsave 时,Redis 会在后台异步进行快照操作,快照同时还可以响应客户端请求。
具体操作是 Redis 进程执行 fork 操作创建子进程(copy-on-write),RDB 持久化过程由子进程负责,完成后自动结束。它不会记录 fork 之后后续的命令。阻塞只发生在fork 阶段,一般时间很短。

用 lastsave 命令可以查看最近一次成功生成快照的时间。

优势:

  • RDB 是一个非常紧凑(compact)的文件,它保存了 redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。
  • 生成 RDB 文件的时候,redis 主进程会 fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘 IO 操作。
  • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

劣势:

  1. RDB数据没办法做到实时持久化(秒级持久化或者命令及持久化)因为 bgsave 每次运行都要执行 fork 操作创建子进程,频繁执行成本过高。
  2. 在一定间隔时间做一次备份,所以如果 redis 意外 down 掉的话,就会丢失最后一次快照之后的所有修改(数据有丢失)。
  3. 如果数据相对来说比较重要,希望将损失降到最小,则可以使用 AOF 方式进行持久化。
AOF持久化

AOF:Redis 默认不开启。AOF 采用日志的形式来记录每个写操作,并追加到文件中,开启后,执行了更改redis服务数据的操作命令时,就会把命令写入到AOF文件中。然后如果要使用AOF文件来恢复数据的话,redis在启动时,会把AOF文件中的所有命令执行一遍,数据就恢复了。

appendonly no  #是否开启aof持久化,默认no不开启。
appendfilename "appendonly.aof"  #生成的aof文件名,目录使用dir来设置。

由于操作系统的缓存机制,AOF数据并没有真正地实时写入到磁盘中,而是进入了系统的硬盘缓存中。什么时候真正写到磁盘要由持久化策略决定。

AOF持久化策略:

#fsync操作表示把数据从硬盘缓存真正写入到磁盘中。
appendfsync everysec #默认everysec 表示每秒执行一次 fsync, 可能会导致丢失这 1s 数据。 通常选择 everysec ,兼顾安全性和效率。
#no 表示不执行 fsync, 由操作系统自行保证数据啥时候同步到磁盘, 速度最快,但是不太安全;因为没有刷到磁盘期间服务器宕机了,就会丢失这段时间的数据,因为没有真正写入到磁盘。
# always 表示每次写入都执行 fsync, 以保证数据同步到磁盘, 效率很低;但是最多会丢失一个命令的数据。

fsync会阻塞主进程。

AOF重写:
由于 AOF 持久化是 Redis 不断将写命令记录到 AOF 文件中,随着 Redis 不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存和磁盘越大以及 AOF 恢复要求时间越长。

AOF文件中可能会有一些无意义的命令,比如对同一个key进行值的设置 set key1 555 设置了1000次,但是其实只要执行最后一次的命令就能达到结果,或者前面又100万条修改key的数据,但是最后一条是flushall命令,恢复数据时前面命令的执行那将没有意义。此时,通过AOF重写可以避免此种无意义的命令执行。并且减小AOF文件大小。

当 AOF 文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。

AOF 文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的 AOF 文件。

配置项解释
auto-aof-rewrite-percentage 100默认值为 100。 aof 自动重写配置, 当目前 aof 文件大小超过上一次重写的 aof 文件大小的百分之多少进行重写, 即当 aof 文件增长到一定大小的时候, Redis 能够调用 bgrewriteaof对日志文件进行重写。 当前 AOF 文件大小是上次日志重写得到 AOF 文件大小的二倍(设置为 100) 时, 自动启动新的日志重写过程
auto-aof-rewrite-min-size 64mbaof自动重写的最小文件大小,默认64mb,避免了达到约定百分比但尺寸仍然很小的情况还要重写,要两个条件都符合才进行重写,默认也就是目前aof文件达到了上一次重写的aof文件大小的2倍,并且目前文件大小要大于等于64mb才进行重写
no-appendfsync-on-rewrite在进行RDB持久化或者AOF重写的时候,是否执行fsync操作,如果设置为yes,那么在进行RDB持久化或者AOF重写的时候,就不会进行fsync操作,无论你设置的是everysec还是always都不会进行fsync操作,如果对应用的延时要求有很高要求的话,可以设置为yes,因为fsync会阻塞redis的主进程,如果在进行RDB持久化或者AOF重写时,会消耗大量的IO资源,从而导致fsync的效率会变低,从而导致redis的正常对外服务性能降低。如果设置为no,那么在RDB持久化和AOF重写期间任然会进行fsync,对数据的安全性更友好,Linux 的默认 fsync策略是 30 秒。 如果设置为yes可能丢失 30 秒数据
aof-load-truncatedaof 文件可能在尾部是不完整的, 当 redis 启动的时候, aof 文件的数据被载入内存。 重启可能发生在 redis 所在的主机操作系统宕机后,尤其在 ext4 文件系统没有加上 data=ordered选项, 出现这种现象。 redis 宕机或者异常终止不会造成尾部不完整现象, 可以选择让 redis退出, 或者导入尽可能多的数据。 如果选择的是 yes, 当截断的 aof 文件被导入的时候,会自动发布一个 log 给客户端然后 load尽可能多的数据。如果是 no,用户必须手动 redis-check-aof 修复 AOF文件才可以,否则会报错。 默认值为 yes。

优势:

  • AOF 持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据而已。

劣势:
1、对于具有相同数据的的 Redis,AOF 文件通常会比 RDF 文件体积更大(RDB
存的是数据快照)
2、虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。在高并发的情况下,RDB 比 AOF 具好更好的性能保证。

持久化策略的取舍

如果可以忍受一小段时间内数据的丢失,毫无疑问使用 RDB 是最好的,定时生成RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。

否则就使用 AOF 重写。但是一般情况下建议不要单独使用某一种持久化机制,而是应该两种一起用,在这种情况下,当 redis 重启的时候会优先载入 AOF 文件来恢复原始的数据,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值