Redis内存淘汰策略
注意过期策略和淘汰策略的区别,内存淘汰是在内存达到设置的最大运行内存之后使用的。
可以分为两大类
- 不进行数据淘汰的策略
- 进行数据淘汰的策略
不进行数据淘汰的策略
noeviction,不进行内存淘汰,直接不提供服务,返回错误
进行数据淘汰的策略
又可以细分为两类
- 在设置了过期时间的数据中进行淘汰
- 在所有数据范围内进行淘汰
在设置了过期时间的数据中进行淘汰
- volatile-random:随机淘汰设置了过期时间的任意键值
- volatile-ttl:优先淘汰设置了过期时间的更早过期的键值
- volatile-lru:淘汰所有设置了过期时间的键值中,最久未使用的键值
- volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值
在所有数据范围内进行淘汰
- allkeys-random:随机淘汰任意键值
- allkeys-lru:淘汰整个键值中最久未使用的键值
- allkeys-lfu:淘汰整个键值中最少使用的键值
类别就这么多,值得一提的是其中的LRU和LFU。
Redis中的LRU
我们知道传统的LRU是用链表进行数据组织的,将用到的键值移到链表前面,每次淘汰链表最后的数据。这样做的缺点是,频繁移动节点会影响性能。
Redis中的LRU采用的是一种近似LRU的做法,目的是为了更好地节约内存。
实现方式是在redis结构体中添加一个额外的字段,用来记录这个数据的最后一次访问时间,当进行内存淘汰的时候,会使用随机采样(默认随机5个)的方式来进行淘汰数据,然后淘汰其中最久未使用的那个。
- 优点:
- 节约空间
- 不用每次移动链表,提升性能
- 缺点
- 缓存污染。比如一次读入了大量的数据,但这些数据只会被读一次,但这些数据会在内存中留存很长一段时间,造成污染。
Redis中的LFU
LFU的核心思想是:如果数据过去被访问多次,那么将来被访问的频率也会更高。
Redis中的LFU,对象头中的24bits的LFU字段被分成两段来存储,高16bits用来存时间戳,低8bits存logc(Logistics Counter),注意logc并不是单纯的访问次数,而是访问频次,logc会随时间推移而衰减。
Redis访问时,logc的变化:
- 先按照上次访问距离当前的时长,来对logc进行衰减
- 然后,再按一定的概率增加logc的值