实战小知识之浅谈LRU

137 阅读1分钟

这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

LRU简述

在日常的业务中,缓存的使用可以说十分常见,小到系统的内存缓存,大到no-sql的Redis

但是缓存直接作用于内存中,总会有满的时候;那么就需要有淘汰机制

4.1什么是LRU

正如上面所说的,缓存的作用就是为了防止用户请求直接击穿DB;

所以缓存的命中率是系统非常重要的指标,如果命中率太低,将会导致用户的查询回流到数据库,造成数据库压力暴增,击穿DB

LRU 是内存管理的一种算法,全程就是Least Recently Used(淘汰最少使用)

  • 也就是顾名思义,最少使用过的数据将会被淘汰
  • 这种算法常用于热点数据,一些频繁被请求的数据;
  • 在日常的业务中,Redis承担着我们的这种算法的实现,当然也不止这种算法实现(可配置),仅作举例

4.2 实现

实现方式千千万,这边仅做伪代码举例

  • 利用HashMap+Node节点,双向链表
    HashMap<key,Node> map = new HashMap<>();
    Node node = new Node(); 
    
  • HashMap存储Key值和value = Node节点;节省了链表的查询劣势
  • add方法:双向链表新增节点,仅需修改前后指针,并考虑头尾极端
  • remove方法:与add方法类似,考虑极端
  • refresh方法:刷新节点,被命中移动到头部;结合remove+add方法
  • put方法:新增节点

其实就是把新增的节点数据加入链表,如果已经存在则命中缓存,移动到头节点,否则插入尾部

4.3 彩蛋

  • LRU的优势在于实现难度不高,对于热点数据效率很高

  • 当然,也会有劣势,如果存在偶发的批量操作,例如查询选中的数据等(当然设计也需要背锅);就有可能导致热点数据被批量覆盖,污染了缓存;致使后续的查询效率低下,击穿缓存

  • 解决方法也有,类似InnoDB的LRU改进

    • 用热点数据区 + 冷数据区

    • 若缓存已满,热数据区的数据插入到冷数据区头结点

    • 淘汰会优先淘汰冷数据区

    • 冷数据区的数据被命中时需要作判断

      • 如果数据在冷数据区的存活时间 > 指定的时间值,则不会移动节点至热数据区头部
      • 如果存活时间 < 指定时间,则代表仅是被冲刷下来的,移动到热数据区