Redis精通系列——LRU算法详述(Least Recently Used - 最近最少使用)(1)

Redis针对上述问题提供了maxmemory配置,这个配置可以指定Redis存储器的最大数据集,通常情况都是在redis.conf文件中进行配置,也可以运行时使用CONFIG SET命令进行一次性配置。

redis.conf文件中的配置项示意图:

image.png

默认情况maxmemory配置项并未启用,Redis官方介绍64位操作系统默认无内存限制,32位操作系统默认3GB隐式内存配置,如果maxmemory 为0,代表内存不受限。

因此我们在做缓存架构时,要根据硬件资源+业务需求做合适的maxmemory配置。

3、内存达到maxmemory怎么办


很显然配置了最大内存,当maxmemory达到了最大上限之后Redis不可能不干活了,那么Redis是怎么来处理这个问题的呢?这就是本文的重点,Redis 提供了maxmemory-policy淘汰策略(本文只讲述LRU不涉及LFU,LFU在下一篇文章讲述),对满足条件的key进行删除,辞旧迎新。

maxmemory-policy淘汰策略:

  • **noeviction:**当达到内存限制并且客户端尝试执行可能导致使用更多内存的命令时返回错误,简单来说读操作仍然允许,但是不准写入新的数据,del(删除)请求可以

  • **allkeys-lru:**从全体key中,通过lru(Least Recently Used - 最近最少使用)算法进行淘汰

  • **allkeys-random:**从全体key中,随机进行淘汰

  • **volatile-lru:**从设置了过期时间的全部key中,通过lru(Least Recently Used - 最近最少使用)算法进行淘汰,这样可以保证未设置过期时间需要被持久化的数据,不会被选中淘汰

  • **volatile-random:**从设置了过期时间的全部key中,随机进行淘汰

  • **volatile-ttl:**从设置了过期时间的全部key中,通过比较key的剩余过期时间TTL的值,TTL越小越先被淘汰

还有volatile-lfu/allkeys-lfu这个留到下文一起探讨,两个算法不一样!

random随机淘汰只需要随机取一些key进行删除,释放内存空间即可;ttl过期时间小先淘汰也可以通过比较ttl的大小,将ttl值小的key进行删除,释放内存空间即可。

那么LRU是怎么实现的呢?Redis又是如何知道哪个key最近被使用了,哪个key最近没有被使用呢?

4、LRU算法实现


我们先用Java的容器实现一个简单的LRU算法,我们使用ConcurrentHashMap做key-value结果存储元素的映射关系,使用ConcurrentLinkedDeque来维持key的访问顺序。

LRU实现代码:

package com.lizba.redis.lru;

import java.util.Arrays;

import java.util.List;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.ConcurrentLinkedDeque;

/**

*      LRU简单实现

* @Author: Liziba

* @Date: 2021/9/17 23:47

*/

public class SimpleLru {

/** 数据缓存 */

private ConcurrentHashMap<String, Object> cacheData;

/** 访问顺序记录 */

private ConcurrentLinkedDeque sequence;

/** 缓存容量 */

private int capacity;

public SimpleLru(int capacity) {

this.capacity = capacity;

cacheData = new ConcurrentHashMap(capacity);

sequence = new ConcurrentLinkedDeque();

}

/**

* 设置值

* @param key

* @param value

* @return

*/

public Object setValue(String key, Object value) {

// 判断是否需要进行LRU淘汰

this.maxMemoryHandle();

// 包含则移除元素,新访问的元素一直保存在队列最前面

if (sequence.contains(key)) {

sequence.remove();

}

sequence.addFirst(key);

cacheData.put(key, value);

return value;

}

/**

* 达到最大内存,淘汰最近最少使用的key

*/

private void maxMemoryHandle() {

while (sequence.size() >= capacity) {

String lruKey = sequence.removeLast();

cacheData.remove(lruKey);

System.out.println("key: " + lruKey + “被淘汰!”);

}

}

/**

* 获取访问LRU顺序

* @return

*/

public List getAll() {

return Arrays.asList(sequence.toArray(new String[] {}));

}

}

测试代码:

package com.lizba.redis.lru;

/**

*      测试最近最少使用

* @Author: Liziba

* @Date: 2021/9/18 0:00

*/

public class TestSimpleLru {

public static void main(String[] args) {

SimpleLru lru = new SimpleLru(8);

for (int i = 0; i < 10; i++) {

lru.setValue(i+“”, i);

}

System.out.println(lru.getAll());

}

}

测试结果:

image.png

最后

一线互联网Android面试题含详解(初级到高级专题)

这些题目是今年群友去腾讯、百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。并且大多数都整理了答案,熟悉这些知识点会大大增加通过前两轮技术面试的几率

如果设置门槛,很多开发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。

最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
多数都整理了答案,熟悉这些知识点会大大增加通过前两轮技术面试的几率

[外链图片转存中…(img-ADu5ja9K-1715685652538)]

如果设置门槛,很多开发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。

最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值