之前的文章聊了一下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文件。
本文深入探讨Redis的内存管理机制,包括内存回收、内存淘汰策略如LRU和随机淘汰,以及过期策略如何结合定期与惰性删除确保高效运行。同时解析持久化过程中对过期key的处理。
1732

被折叠的 条评论
为什么被折叠?



