过期删除策略
Redis 是可以对 key 设置过期时间的,因此需要有相应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略
过期时间设置
expire key n
:n秒后过期pexpire key n
:n毫秒后过期expireat key n
:n时间戳时(秒)过期pexpireat key n
:n时间戳时(耗秒)过期ttl key
:查看过期时间
字符串特有的过期时间设置:
set key n value
:n秒后过期set key value ex n
:n秒后过期set key value px n
:n毫秒后过期
如何判断时候过期
当数据插入到redisdb.dict
哈希表中时,如果他设置了过期时间,那么也会被插入到另外一个过期字典里,过期字典就是另外一个哈希表,哈希表的最大好处就是让我们可以用 O(1) 的时间复杂度来快速查找。当我们查询一个 key 时,Redis 首先检查该 key 是否存在于过期字典中:
- 如果不在,则正常读取键值;
- 如果存在,则会获取该 key 的过期时间,然后与当前系统时间进行比对,如果比系统时间大,那就没有过期,否则判定该 key 已过期。
过期策略
- 定时删除:设置expire时,启动一个定时任务,到时唤起cpu触发任务
- 优点:节约内存
- 缺点:CPU任务重,减少吞吐量
- 惰性删除:查询数据时,判断过期时间
- 优点:CPU任务轻
- 缺点:内存占用量大,如果过期未查询就会一直占用内存
- 定期删除:每隔一段时间,随机抽取部分key判断后删除
- 优点:通过限制删除操作执行的时长和频率,来减少删除操作对 CPU 的影响,同时也能删除一部分过期的数据减少了过期键对空间的无效占用。
- 缺点1:内存清理方面没有定时删除效果好,同时没有惰性删除使用的系统资源少。
- 缺点2:难以确定删除操作执行的时长和频率。如果执行的太频繁,定期删除策略变得和定时删除策略一样,对CPU不友好;如果执行的太少,那又和惰性删除一样了,过期 key 占用的内存不会及时得到释放。
Redis过期策略什么
Redis 选择「惰性删除+定期删除」这两种策略配和使用
这个间隔检查的时间是多长呢?
在 Redis 中,默认每秒进行 10 次过期检查一次数据库,此配置可通过 Redis 的配置文件 redis.conf 进行配置,配置键为 hz 它的默认值是 hz 10。
定期删除流程
- 从过期字典中随机抽取 20 个 key;
- 检查这 20 个 key 是否过期,并删除已过期的 key;
- 如果本轮检查的已过期 key 的数量,超过 5 个(20/4),也就是「已过期 key 的数量」占比「随机抽取 key 的数量」大于 25%,则继续重复步骤 1;如果已过期的 key 比例小于 25%,则停止继续删除过期 key,然后等待下一轮再检查。
内存淘汰策略
内存淘汰设置
内存淘汰是指当内存占用过大,需要释放部分内存。
淘汰分成2大类:
- 不进行数据淘汰(redis默认):当内存超过最大设置内存时,插入数据会返回错误
- 进行数据淘汰:当内存超过最大设置内存时,部分内存被释放
进行数据淘汰 类型
volatile-random
:随机淘汰设置了过期时间的任意键值volatile-ttl
:优先淘汰更早过期的键值volatile-lru
:淘汰设置了过期时间的键值中最久未使用的键值volatile-lfu
:淘汰所有设置了过期时间的键值中,最少使用的键值;allkey-random
:随机淘汰任意键值allkey-lru
:随机淘汰最久未使用的键值allkey-lfu
:淘汰整个键值中最少使用的键值
不进行数据淘汰
noeviction
:不淘汰键值,插入时报错(Redis默认)
LRU
正常实现LRU
LRU 全称是 Least Recently Used 翻译为最近最少使用,会选择淘汰最近最少使用的数据。
传统LRU是通过链表,使用时将数据插入链表头部,需要淘汰时,从链表尾部删除
缺点
- 所有缓存数据都需要链表管理,占用空间大
- 当访问数据时,需要遍历链表查找到访问元素,并移除插入到头部O(n)。耗时严重呢
redis中实现
redis是在所有节点中添加一个最后访问时间。
当 Redis 进行内存淘汰时,会使用随机采样的方式来淘汰数据,它是随机取 5 个值(此值可配置),然后淘汰最久没有使用的那个。
Redis 实现的 LRU 算法的优点:
- 不用为所有的数据维护一个大链表,节省了空间占用;
- 不用在每次数据访问时都移动链表项,提升了缓存的性能
LFU
LFU 全称是 Least Frequently Used 翻译为**最近最不常用的,**LFU 算法是根据数据访问次数来淘汰数据的,它的核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。