Redis数据缓存的LRU实现机制

简介Redis系统的LRU算法在淘汰数据时, 使用的是一种近似算法,并不是严格的按照访问时间进行缓存数据的淘汰。 哈希表字段expires存储具有超时属性的数据,哈希表字段dict既存储没有超时属性的数据, 也存储具有超时属性的数据,即哈希表dict中存储的是全量的缓存数据。 Redis系统提供五种淘汰策略,即参数maxmemory_policy有五种取值: noeviction: 如果缓存数据超过了maxmemory限定值,并且客户端正在执行的命令会导致内存分配,则向客户端返回错误响

Redis系统的LRU算法在淘汰数据时, 使用的是一种近似算法,并不是严格的按照访问时间进行缓存数据的淘汰。

哈希表字段expires存储具有超时属性的数据,哈希表字段dict既存储没有超时属性的数据, 也存储具有超时属性的数据,即哈希表dict中存储的是全量的缓存数据。

Redis系统提供五种淘汰策略,即参数maxmemory_policy有五种取值:

noeviction: 如果缓存数据超过了maxmemory限定值,并且客户端正在执行的命令会导致内存分配,则向客户端返回错误响应.
allkeys-lru: 所有的缓存数据(包括没有超时属性的和具有超时属性的)都参与LRU算法淘汰.
volatile-lru: 只有超时属性的缓存数据才参与LRU算法淘汰.
allkeys-random: 所有的缓存数据(包括没有超时属性的和具有超时属性的)都参与淘汰, 但是采用随机淘汰,而不是用LRU算法进行淘汰.
volatile-random: 只有超时属性的缓存数据才参与淘汰,但是采用随机淘汰,而不是用LRU算法进行淘汰.
volatile-ttl: 只有超时属性的缓存数据才参与淘汰. 根据缓存数据的超时TTL进行淘汰,而不是用LRU算法进行淘汰.
因为volatile-lru, volatile-random和volatile-ttl这三个淘汰策略使用的不是全量的缓存数据,有可能无法淘汰出足够的内存空间.

因为将缓存数据设置超时属性占用更多的内存, 因此,当内存压力比较大的时候,需要慎重考虑设置超时属性。


如果淘汰策略是allkeys-random或者volatile-random,则从相应数据库中随机选择一个key进行淘汰.
如果淘汰策略是allkeys-lru或者volatile-lru, 则根据配置的采样值maxmemory_samples,随机从数据库中选择maxmemory_samples个key, 淘汰其中热度最低的key对应的缓存数据.
如果淘汰策略是volatile-ttl,则根据配置的采样值maxmemory_samples,随机从数据库中选择maxmemory_samples个key,淘汰其中最先要超时的key对应的缓存数据.
所以采样参数maxmemory_samples配置的数值越大, 就越能精确的查找到待淘汰的缓存数据,但是也消耗更多的CPU计算,执行效率降低.

Redis系统没有使用一个全局的链表将所有的缓存数据管理起来,而是使用一种近似的算法来模拟LRU淘汰的效果, 个人认为其原因有:

首先可以节省内存占用.如果用全局的双向链表管理所有的缓存数据,则每个节点的两个指针字段将增加16字节(64位系统上).
Redis系统中不同对象实现的可能是不同的结构,有的是比较复杂的复合结构. 如果再引入一个全局的链表,将增加代码复杂性,可读性也变差.




本文转自:https://blog.csdn.net/azurelaker/article/details/85045245