当前位置:科技动态 > 【第93期】经典面试题:Redis内存满了怎么办?

【第93期】经典面试题:Redis内存满了怎么办?

  • 发布:2023-10-05 20:09

2022年5月17日下午3:48 • 面试问题 • 阅读 4 点击上方“Java面试题精选”,关注公众号 面试时画图,查漏补缺 >>额外编号:以前的面试题,10道为单位,放在这个公众号菜单栏->面试题中。如果您需要它们,欢迎您阅读。 Redis占用内存大小 我们知道Redis是一个基于内存的键值数据库。由于系统的内存大小是有限的,我们在使用Redis时可以配置Redis可以使用的最大内存大小。 1.通过配置文件进行配置 设置内存大小,在Redis安装目录下的redis.conf配置文件中添加如下配置。 //设置Redis最大内存大小为100Mmaxmemory 100mb redis配置文件不一定使用安装目录下的redis.conf文件。启动redis服务时,可以传递一个参数来指定redis配置文件。 2.通过命令修改 Redis支持运行时通过命令动态修改内存大小 //设置Redis占用的最大内存大小为100M127.0.0.1:6379> config set maxmemory 100mb//获取Redis可以使用的最大内存大小 127.0.0.1:6379> config get maxmemory 如果不设置最大内存大小或者将最大内存大小设置为0,则64位操作系统下对内存大小没有限制,32位操作系统下最大可以使用3GB内存系统。 Redis内存过时 由于可以设置Redis的最大内存大小,因此存在配置的内存用完的情况。那么当内存耗尽的时候,我们继续往Redis中添加数据,不就没有内存可用了吗? 事实上,Redis定义了几种策略来处理这种情况: noeviction(默认策略):不再为写请求提供服务,直接返回错误(DEL请求和一些特殊请求除外) allkeys-lru:使用LRU算法从所有key中消除 volatile-lru:使用LRU算法淘汰设置了过期时间的key allkeys-random:随机消除所有键中的数据 volatile-random:随机淘汰设置过期时间的keyvolatile-ttl:在设置了过期时间的key中,会根据key的过期时间进行淘汰。到期日越早,淘汰的优先级越高。 当使用 volatile-lru、volatile-random 和 volatile-ttl 三种策略时,如果无法消除任何 key,则会返回与 noeviction 相同的错误。 如何获取和设置内存淘汰策略 获取当前的内存消除策略: 127.0.0.1:6379> 配置获取最大内存策略 通过配置文件设置淘汰策略(修改redis.conf文件): 最大内存策略 allkeys-lru 通过命令修改淘汰策略: 127.0.0.1:6379> 配置集 maxmemory-policy allkeys-lru LRU算法 什么是LRU? 上面提到,当Redis可用的最大内存用完时,可以使用LRU算法来淘汰内存。那么什么是LRU算法呢? LRU(Leastmostlyused),即最近最少使用,是一种缓存替换算法。当使用内存作为缓存时,缓存的大小一般是固定的。当缓存满了,继续向缓存添加数据时,需要淘汰一些旧数据,释放内存空间来存储新数据。 这时候就可以使用LRU算法了。其核心思想是:如果一条数据在最近一段时间内没有被使用过,那么未来被使用的可能性很小,因此可以将其淘汰。 使用java实现一个简单的LRU算法 public class LRUCache { //容量 private int 容量; //统计当前有多少个节点 private int count; //缓存节点 private Map> nodeMap;私有节点头;私有节点尾部;public LRUCache(int capacity) { if (capacity < 1) {            throw new IllegalArgumentException(String.valueOf(capacity));        }        this.capacity = capacity;        this.nodeMap = new HashMap<>(); //初始化头节点和尾节点,使用哨兵模式,减少判断头节点和尾节点是否为空的代码 Node headNode = new Node (null, null) ; 节点 tailNode = new Node(null, null); www.sychzs.cn = tailNode; tailNode.pre = headNode; this.head = headNode; this.tail = tailNode; } public void put(k key, v value) { Node node = nodeMap.get(key); if (node == null) { if (count >=capacity) { 先删除一个节点removeNode() ; moveNodeToHead(节点); public Node get(k key) { Node node = nodeMap.get(key); if (node != null) { moveNodeToHead(node);返回节点; }private voidremoveNode(){        节点node = tail.pre; //从链表里面移除        removeFromList(node); nodeMap.remove(node.key);数数 - ; } private void removeFromList(Node node) {        Node pre = node.pre;节点下一个=www.sychzs.cn; 前.下一个 = 下一个;下一个.pre = pre; 节点.next = null;节点.pre = null; } private void addNode(Node node) {        //添加节点到头部        addToHead(node); nodeMap.put(node.key, 节点);计数++; } private void addToHead(Nodenode){        Node next = www.sychzs.cn;下一个.pre=节点;节点.下一个 = 下一个;节点.pre = 头; www.sychzs.cn = 节点; } public void moveNodeToHead(Node node) {        //从链表里面移除        removeFromList(node); // 添加节点到头部        addToHead(node); } 类 Node {        k 键; v 值;节点预;下一个节点;public Node(k key, v value) { this.key = key; this.value = 值; } }} 上面的代码实现了一个简单的LUR算法。代码很简单,有注释。只要仔细看就很容易理解。 Redis中LRU的实现 近似LRU算法 Redis采用近似LRU算法,与常规LRU算法不太一样。近似LRU算法通过随机采样来消除数据,每次随机选择5个(默认)key,并消除最近最少使用的key。 样本数量可以通过 maxmemory-samples 参数修改: 示例:最大内存样本 10 maxmenory-samples配置越大,淘汰结果越接近严格的LRU算法。 为了实现近似的LRU算法,Redis为每个key添加了一个额外的24位字段来存储该key最后一次被访问的时间。 Redis3.0近似LRU的优化 Redis3.0对近似LRU算法做了一些优化。新算法将维护一个候选池(大小为 16)。池中的数据按照访问时间排序。第一个随机选择的密钥将被放入池中。仅当访问时间小于池时,才会选择随后随机选择的每个密钥。最短时间将被放入池中,直到候选池满为止。当它满了的时候,如果有新的key需要放入,那么最后访问时间最长的(最近访问过的)就会从池中移除。 当需要淘汰时,只需从池中选择最近访问时间最小的key(最长时间没有被访问过的key)并淘汰即可。 LRU算法比较 我们可以通过实验来比较各个LRU算法的准确率。首先向Redis添加一定量的数据n以耗尽Redis的可用内存,然后向Redis添加n/2个新数据。这个时候就需要剔除一部分。如果对数据遵循严格的LRU算法,则应消除添加的前n/2个数据。 生成如下各个LRU算法的对比图 图片来源:www.sychzs.cn/a/1190000017555834 可以看到图中有三个不同颜色的点: 浅灰色为淘汰数据 灰色为尚未淘汰的旧数据 绿色为新添加的数据 我们可以看到,采样数为10的Redis3.0生成的图最接近严格LRU。并且使用相同数量的5个样本,Redis3.0也优于Redis2.8。LFU算法 LFU算法是Redis4.0中新添加的淘汰策略。它的全称是“LeastFrequentlyUsed”,其核心思想是根据键最近被访问的频率来淘汰。首先淘汰很少访问的密钥,并保留访问较多的密钥。 LFU算法可以更好地表示被访问的密钥的流行度。如果使用LRU算法,某个key长期没有被访问过,只是偶尔被访问过,那么它就被认为是热数据,不会被淘汰,而且有些key以后很可能会被访问​​到。被淘汰了。如果使用LFU算法就不会出现这种情况,因为使用一次并不会让某个key成为热点数据。 LFU 有两种策略: volatile-lfu:使用LFU算法淘汰设置了过期时间的key中的key。 allkeys-lfu:使用LFU算法消除所有key中的数据 设置和使用这两种消除策略与之前提到的相同,但需要注意的是,这两周的策略只能在Redis 4.0及以上版本中设置。如果设置在Redis 4.0以下,会报错。 问题 最后我留下一个小问题。有些人可能注意到了,我在文章中并没有解释为什么Redis使用近似LRU算法而不是精确LRU算法。您可以在评论区给出您的答案,让我们一起讨论学习。 参考 https://www.sychzs.cn/topics/lru-cache https://www.sychzs.cn/a/1190000016743562 https://www.sychzs.cn/a/1190000017555834 来源:www.sychzs.cn/post/5d674ac2e51d4557ca7fdd70 最后五期 【第88期】面试官问:能告诉我spring中接口bean是怎么注入的吗? 【第89期】面试官5问一个TCP连接可以发送多少个HTTP请求? 【第90期】面试官:说说用Redis实现大规模帖子浏览量统计的想法。 【第91期】面试官:Spring使用了哪些设计模式?就说三种 【第92期】面试官:你说你精通Java并发,那给我讲讲J.U.C吧。 而不是在网上搜索问题?还不赶快关注我们吧~版权声明:本文内容由网友自愿贡献,本文所表达的观点仅代表作者自己的观点。本网站仅提供信息存储空间服务,不拥有任何所有权,也不承担相关法律责任。如果您发现本站有任何涉嫌侵权/非法内容,请发送邮件举报。一经核实,该网站将立即删除。 本文由斑马博客整理。本文链接为:https://www.sychzs.cn/index.php/post/6876.html

相关文章

热门推荐