LRU算法概述

前言

互联网项目为了提升系统吞吐量,同时为了减少数据库的负载压力,通常会引入缓存,比如缓存用户的姓名、头像、等级等等之类的信息。在绝大部分的情况下(百万级用户),这么做都是没问题的,实现简单,同时也高效。但是当我们的系统用户量达到千万级以后,这么做就会遇到如下问题:

  1. 占用内存过大,容易挤爆内存,同时内存又是非常稀缺有昂贵的资源
  2. 针对用户信息进行全量缓存,并不一定所有的缓存都被利用,如果你们app的用户量达到百万级,同时日活达到20W,你们的app就已经很成功了。但是会浪费绝大部分的资源,如果用户量达到千万级,缓存命中率可能会更低

如何解决上面这两点问题,针对1来说,为了防止内存被挤满,我们可以设置一个阀值。当缓存到某个程度容量,就清除一半的缓存;但是对于2来说,如果我们清除的缓存,属于活跃内存,又会导致去数据库查询,适得其反。

所以我们需要一种淘汰策略,针对百万级用户,日活20W的用户量来说:我们缓存最近活跃的30W用户的信息,那么不就完美的解决了上面的两点了吗?

实现思路

好了我们现在需求有了,缓存最近活跃的30W用户的信息。但是如何实现呢?

需求:我们需要一种容器,这种容器它是定容的(30W容量),同时它又是有序的(针对用户插入容器的顺序,节点越再后面,说明节点越新),同时它又有很高的查询性能。

LRU算法其实就是解决我们上面这个需求的,LRU全程Least Recently Used,字面意思就是最近最少使用,通常用于缓存的淘汰策略实现,因为内存资源非常宝贵,所以需要根据某种规则定期清除防止内存被撑满。

LRU算法的精妙之处是因为它采用了一种了LinkedHashMap的哈希链表,它是一种有序的哈希表,使之前物理和逻辑上无序的哈希表,再给每个节点加入了一个,加入了一个前驱后继指针后,便形成了逻辑上的连续,我们通过定义的一个头结点就可以依次的遍历整个哈希表,如下图(图片来自:https://www.cnblogs.com/xiaoxi/p/6170590.html):
LinkedHashMap结构图

执行流程

LRU算法具体是怎么实现的呢,我们以用户信息为例,来进行演示一下:

  1. 我们现在有一个容量为5的哈希链表,第一次依次插入5个用户
    在这里插入图片描述

  2. 这时候我们需要访问id为002的用户信息,哈希链表首先把id为002的用户从哈希链表中移除,之后添加到哈希表的最末端
    在这里插入图片描述
    在这里插入图片描述

  3. 这时候,我们需要查询006用户的信息,但是006用户的信息哈希链表中没有,我们从数据库中查询出来之后添加到哈希链表的最末端。但是这个时候超出了哈希链表的最大容量5,那么就需要移除哈希链表最左端的节点,使之不会超出最大容量。
    在这里插入图片描述
    在这里插入图片描述

这样我们就实现了一个容量为5,而最右边是最近使用节点的一种容器,这就是我们LRU算法的基本思路

具体实现

LRU算法也有很多的实现的,上文也说了jdk中自带的LinkedHashMap是天然的最近最少模型容器,但是LinkedHashMap不是线程安全的,在使用的注意线程安全问题。

对于用户系统Redis也给我们提供了类似LRU收集算法的实现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值