一、服务器中的数据库
二、键的过期
Redis 可以设置键的生存时间或过期时间。
RedisDB 结构中的expires字典保存了数据库中所有键的过期时间,称这个字典为过期字典。
2.1 Redis 的过期键删除策略
Redis 服务器实际使用惰性删除和定期删除两种策略。通过配合两种删除策略,可以在CPU时间和避免浪费内存空间之间取得平衡。
2.2 惰性删除策略的实现
2.3 定期删除策略的实现
2.4 RDB 持久化对过期键的处理
2.5 AOF 持久化对过期键的处理
2.6 复制对过期键的处理
从服务器不删除过期键的目的是保证主从服务器数据的一致性。
三、数据淘汰策略
Redis 可以设置内存最大使用量maxmemory
,当内存使用量超出时,会施行数据淘汰策略。
Redis 具体有 6 种淘汰策略
volatile-lru
: 从已设置过期时间的数据集中挑选最近最久使用的数据淘汰volatile-ttl
: 从已设置过期时间的数据集中挑选将要过期的数据淘汰volatile-random
: 从已设置过期时间的数据集中随机选择数据淘汰allkeys-lru
: 从所有数据集中挑选最近最久使用的数据淘汰allkeys-random
: 从所有数据集中随机数据进行淘汰noeviction
: 禁止驱逐数据
执行if (mem_used <= server.maxmemory) return REDIS_OK;
如果当前缓存数据占用的总的内存小于配置的maxmemory
,则不用淘汰,直接返回。
如果当前缓存的数据使用的内存大于配置的maxmemory
,并且淘汰策略不允许释放内存noeviction
,则该函数返回失败。
接下来,局部变量mem_tofree
表示需要淘汰的内存,局部变量mem_freed
表示已经淘汰的内存。循环执行while (mem_freed < mem_tofree)
淘汰缓存数据,该循环中的逻辑可以概括为:
- 从全局的0号数据库开始(Redis默认有16个全局的数据库),根据淘汰策略,选择该数据库中的哈希表。如果该哈希表为空,选择下一个全局数据库。
- 根据淘汰策略,在相应哈希表中找到一个待淘汰的key,从该数据库对象中删除该key所对应的缓存数据。
- 如果没有找到待淘汰的key,即无法淘汰所需的缓存数据大小,函数直接返回错误。
- 如果当前访问的是最后一个全局数据库,并且已经淘汰了所需的缓存数据,则该函数成功返回。如果没有淘汰所需的缓存数据,则返回步骤1,并且从0号数据库重新淘汰。如果当前访问的不是最后一个全局数据库,则返回步骤1,从当前数据库的下一个数据库继续淘汰缓存数据。
如果淘汰策略是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计算,执行效率降低。
使用LRU算法时会用到redisObject
的lru
属性,记录对象上次使用的时间。
使用 Redis 缓存数据时,为了提高缓存命中率,需要保证缓存数据都是热点数据。可以将内存最大使用量设置为热点数据占用的内存量,然后启用 allkeys-lru
淘汰策略,将最近最少使用-LRU的数据淘汰。
Redis 4.0 引入了 volatile-lfu
和 allkeys-lfu
淘汰策略,LFU 策略通过统计访问频率,将访问频率最少的键值对淘汰。