1、Redis的内存回收
在Redis
中可以设置key的过期时间,以期可以让Redis
回收内存,循环使用。在Redis
中有4个命令可以设置Key的过期时间。分别为 expire
、pexpire
、expireat
、pexpireat
。
1.1、expire
expire key ttl:将key的过期时间设置为ttl秒。
1.2、pexpire
pexpire key ttl:将key的过期时间设置为ttl毫秒。
1.3、expireat
expireat key timestamp:将key的过期时间设置为指定的timestamp(时间戳,秒)。
1.4、pexpireat
pexpireat key timestamp:将key的过期时间设置为指定的timestamp(时间戳,毫秒)。
PS:不论使用的是哪个命令。 Redis
最终都是使用pexpireat
命令实现。
1.5、ttl
ttl key:查看key剩余过期时间(秒)
1.6、pttl
pttl key:查看key的剩余过期时间(毫秒)
PS:如果未设置过期时间,则返回-1,如果key不存在,则都返回-2。
RedisDb结构体定义:
c
typedf struct redisDb{
dict *dict; //数据库的键空间,保存数据库中的所有键值对
dict *expires; //保存所有过期的键
dict *blocking_keys; //keys for clients waiting for data(blpop)
dict *ready_keys; //Blocked keys that received PUSH
dict *watched_Keys; //watched keys for multi/exec cas
int id; //数据库ID字段,代表不同的数据库
long long avg_ttl; //average TTL, just for stats
}redisDb;
2、Redis的过期策略
2.1、定时删除
为每个key创建一个定时任务,一旦到达过期时间,就立即删除。该策略可以立即清除掉过期的key,对内存友好,但是对CPU不友好,回影响Redis
的吞吐量和响应时间。
2.2、惰性删除
当访问一个key时,才判断这个key是否过期,如果过期的话,就删除。该策略能最大的节省CPU的资源。但是对内存不是很友好,极端情况下,可能存在大量的key已经过期,但是由于在过期后就没有被访问过,导致无法被删除。
2.3、定期删除
每个一段时间,扫描Redis
中过期key
字典(expires),并清除部分过期的key。该策略是前两者的一个折中方案,可以通过调整定时扫描的时间时间和每次扫描的限定耗时,在不同情况下使得CPU和内存资源达到最优平衡。
在Redis中,同时使用了惰性删除和定期删除。
3、Redis淘汰策略
Redis
的内存淘汰策略,是指内存达到maxmemory极限时,使用某种算法来决定清理掉哪些数据,以保证新数据的写入。
3.1、Redis的内存淘汰机制
- no-eviction:当内存不足写入新数据时,新写入操作会报错。
- allkeys-lru:当内存不足以写入新数据时,在所有的key中,采用LRU算法删除最近最少使用的key。
- allkeys-random:当内存不足以写入新数据时,在所有的key中,随机删除某个key。
- volatile-lru:当内存不足以写入新数据时,在设置了过期时间的key中,采用lru算法删除最近最少使用的key。
- volatile-random:当内存不足以写入新数据时,在设置了过期时间的key中,随机删除某个key。
- volatile-ttl:当内存不足以写入新数据时,在设置了过期时间的key中,删除最快过期的key删除。
- volatile-lfu:当内存不足以写入新数据时,在设置了过期时间的key中,删除使用频率最少的的key。
- allkeys-lfu:当内存不足以写入新数据时,在所有的key中,采用lfu算法删除使用频率最少的key。
3.2、LRU算法-标准实现
标准的LRU实现方式:
- 添加新的数据时,会将新数据放到链表的头部。
- 当数据被访问时,被访问的数据会被放到链表的头部。
- 当链表满时,会将链表尾部的数据删除。
正常的LRU
算法的实现是采用Map
+双向链表的方式实现的。也即是在访问数据时,先使用map
判断下是否存在,如果存在,则将被访问的数据移动到链表的头部。如果添加数据,会现在链表的头部添加,成功之后,在放到map
中。
3.3、LRU算法-Redis实现
Redis
中的LRU
算法并不是标准的LRU
算法,而是一种近似LRU
算法。在Redis3.0
之前,Redis
是随机取出若干个key(默认是5个,可以通过maxmemory-samples
配置),然后删除取出key中最久被访问的那个key。
在Redis3.0
之后,改进了LRU
算法的实现,采用维护一个回收候选键池的方式。
- 首先,第一次随机取的key会被放到一个pool中(pool的大小为16),pool中的key是按照key的最近访问的时间排序的(lru)。接下来每次随机取的key,lru值都必须小于pool中最小的lru才能被继续放入。放满之后,每次如果有新的key需要放入,需要将pool中lru最大的一个key取出。
- 淘汰的时候,直接从pool中选出一个lru最小的key进行删除。