之前的文章聊了一下redis的基本数据结构和两种特殊的数据结构,这篇文章主要分析一下redis的内存淘汰机制和缓存过期策略。

缓存就是第一次请求数据库之后直接将取到的数据放到内存中,然后每次从内存中取数据,从而加快了速度,直接的提高了程序的性能。那么也带了一个问题,随着数据越来越多内存占用就会越来越大,因为内存是有限的,如果不约定一些内存淘汰机制和过期策略,内存很快就会被撑爆了。

<>内存回收机制

因为C语言不具备内存自动回收的功能,所以redis在自己的对象系统中构建了一个引用计数技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收
typedef struct redisObject { // 引用计数 int refcount; } robj;
对象的引用计数信息会随着对象的使用状态不断变化:

* 创建对象的时候,引用计数的值会被初始化为1
* 当对象被一个新程序使用时,它的引用计数值会被+1
* 当对象不再被一个程序使用时,它的引用计数值会被-1
* 当对象的引用计数值变为0时,对象所占用的内存会被释放
<>内存淘汰机制

Redis在使用内存达到某个阈值(通过maxmemory配置)的时候,就会触发内存淘汰机制,选取一些key来删除。内存淘汰有许多策略,下面分别介绍这几种不同的策略。
# maxmemory <bytes> 配置内存阈值 # maxmemory-policy noeviction
* noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。默认策略
* allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。
* allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
* volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
* volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
* volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
在平时的业务开发中推荐使用allkeys-lru和volatile-lru两种过期策略。

LRU是Least Recently
Used的缩写,即最近最少使用。LRU源于操作系统的一种页面置换算法,选择最近最久未使用的页面予以淘汰。在Redis里,就是选择最近最久未使用的key进行删除。

<>过期策略

用过redis的都知道,设置key的时候可以设置key的过期时间,那么key到了约定的过期时间就会立即失效吗?答案:不是的。

Redis是使用定期删除+惰性删除两者配合的过期策略。

* 定期删除
所谓定期删除,redis是这样子做的。每隔100ms就会随机抽取
扫描设置了过期时间的key,判断这些key是不是已经过期了,如果过期了就删除。那为什么不直接删除掉所有过期的key呢?因为key量很大的时候全盘扫描key会很消耗性能,所以还需要配合惰性删除。

* 惰性删除

所谓惰性删除不再是主动删除。就是客户端请求某个key的时候,redis会去判断key是否失效,如果失效了就删除,没失效就返回给客户端。所以惰性删除可以解决一些过期了,但没被定期删除随机抽取到的key。但有些过期的key既没有被随机抽取,也没有被客户端访问,就会一直保留在数据库,占用内存,长期下去可能会导致内存耗尽。所以可以使用上面提到的
内存淘汰机制来解决。

<>持久化时对过期key的处理

* RDB

在持久化key之前会检查key是否过期,如果key已过期,就不会持久化到RDB中。同理,从RDB恢复数据时也会检查key是否过期,如果过期了也不会恢复到数据库中。

* AOF

在持久化key之前,key已经失效但是没有执行del命令,不会持久化到AOF中(因为没有在AOF中追加del命令)。当key已经失效执行了del命令的时候,会在AOF中追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉)。重写时,会先判断key是否过期,已过期的key不会重写到aof文件。

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信