Redis内存淘汰策略
Redis是基于内存的K-V数据库,因为系统的内存大小有限,所以在使用Redis的时候能配置Redis能使用的内存的大小。
Redis占用内存的大小
- 通过配置文件修改
通过修改在Redis安装目录下面的redis.conf配置文件中添加一下配置设置内存的大小
//设置redis占用系统的内存为100MB
maxmemory 100mb
- 通过指令修改
Redis支持运行时通过命令动态修改内存大小
//设置Redis最大内存大小为100MB
127.0.0.1:6379> config set maxmemory 100mb
//获取设置的Redis能使用的内存大小
127.0.0.1:6379> config get maxmemory
如果不设置Redis内存的大小或者设置Redis内存的大小为0,在64位系统下将不限制内存的大小,在32位操作系统下最多使用3GB内存
Redis的内存淘汰
既然Redis的内存可以设置,那么配置的内存就有用完的时候,如果在Redis内存用尽的时候继续往Redis中添加数据,这时Redis会如何处理?
Redis定义了几种策略来处理这种情况:
- noeviction(默认策略):对于写请求不在提供服务,直接返回错误(DEL请求和部分特殊请求除外)
- allkeys-lru:所有key使用LRU算法进行淘汰
- volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰
- allkeys-random:从所有key中随机淘汰
- volatile-random:从设置了过期时间的key中进行随机淘汰
- volatile-ttl:在设置了过期时间的key中,根据key的过期时间进行淘汰,越早过期的key越优先被淘汰
当使用volatile-lru、volatile-random、volatile-ttl这三策略时,如果没有key可以被淘汰,则和noeviction一样返回错误。
如何获取及设置内存淘汰策略
获取当前内存淘汰策略:
127.0.0.1:6379> config get maxmemory-policy
通过配置文件设置淘汰策略(修改redis.conf文件):
maxmemory-policy allkeys-lru
通过命令修改淘汰策略:
127.0.0.1:6379> config set maxmemory-policy allkeys-lru
LRU算法
什么是LRU?
LRU(Least Recently Used),即最近最少使用,是一种缓存置换算法。在使用内存作为缓存的时候,缓存的大小一般是固定的,当缓存被占满,这时候继续往内存中添加数据,就需要淘汰一部分老数据,释放内存空间来存储新的数据。这时候就可以使用LRU算法,其核心思想是:如果一个数据在最近一段时间没有被用到,那么将来被使用的可能性也很小,所以可以被淘汰。
LRU在Redis中的实现
近似LRU算法
Redis使用的是近似LRU算法,他和常规的LRU算法不太一样,近似LRU算法通过随机采样法淘汰数据,每次随机出5(默认)个key,从里面淘汰掉最近最少使用的key。
可以通过maxmemory-samples参数修改采样数量: 例:maxmemory-samples 10
maxmemory-samples配置的越大,淘汰结果越接近于严格的LRU算法。
Redis为了实现近似LRU算法,给每个key增加了一个24bit的字段,用来存储该key最后一次被访问的时间。
Redis3.0对近似LRU算法进行了优化
Redis3.0对近似LRU算法进行了优化,新算法会维护一个候选池(大小为16),池中的数据按访问时间排序,第一次随机选取key都会放入池中,随后每次随机选取的key只有在访问时间小于池中的key的访问时间时才会被放入池中,知道侯选池被放满。挡放满后,如果有新的key需要放入,则将池中最后访问时间最大(最近被访问)的移除。
当需要被淘汰的时候,则直接从池中选取访问时间最小(最久没被访问)的key进行淘汰。
经过对比后(Theoretical LRU、Approx LRU Redis3.0 10samples、Approx LRU Redis2.8 5samples、Approx LRU Redis3.0 5samples)得出结论是Redis3.0采样数是10的时候,最接近于严格的LRU算法,同样使用采样数据为5的时候,Redis3.0也优于2.8。
LFU算法
LFU算法是Redis4.0里面最新的一种淘汰策略。它的全称是Least Frequently Used,它的核心思想就是根据key的最近被访问频率进行淘汰,很少被访问的优先被淘汰,被访问的多的则被留下来。
LFU算法更好的表示了一个key的被访问热度,当使用LRU算法的时候,一个key很久没被使用,刚刚偶尔使用了一次,那么它就会被认为是热点数据,不会被淘汰,而有些key将来可能被访问到,却被淘汰了,如果使用LFU算法就不会出现这种情况,因为其算法不会因使用一次就会将key定义为热点key。
LFU一共两种策略:
- volatile-lfu:在设置了过期时间的key中使用LFU算法淘汰key
- allkeys-lfu:在所有的key中使用LFU算法进行淘汰数据
设置使用这两种淘汰策略的时候要的一点是这两种策略只能在Redis4.0及以上的版本设置,在Redis4.0以下的版本使用会报错
为何Redis使用近似LRU算法而不直接使用LRU算法?
因为近似LRU算法只是把随机采样的key进行访问时间排序,精确LRU需要全局排序,代价太大,结果相近,所以Redis选择了近似LRU算法。