这是我参与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改进
-
用热点数据区 + 冷数据区
-
若缓存已满,热数据区的数据插入到冷数据区头结点
-
淘汰会优先淘汰冷数据区
-
冷数据区的数据被命中时需要作判断
- 如果数据在冷数据区的存活时间 > 指定的时间值,则不会移动节点至热数据区头部
- 如果存活时间 < 指定时间,则代表仅是被冲刷下来的,移动到热数据区
-