mysql缓存淘汰机制_聊聊缓存淘汰算法-LRU 实现原理

前言

我们常用缓存提升数据查询速度,由于缓存容量有限,当缓存容量到达上限,就需要删除部分数据挪出空间,这样新数据才可以添加进来。缓存数据不能随机删除,一般情况下我们需要根据某种算法删除缓存数据。常用淘汰算法有 LRU,LFU,FIFO,这篇文章我们聊聊 LRU 算法。

LRU 简介

LRU 是 Least Recently Used 的缩写,这种算法认为最近使用的数据是热门数据,下一次很大概率将会再次被使用。而最近很少被使用的数据,很大概率下一次不再用到。当缓存容量的满时候,优先淘汰最近很少使用的数据。

假设现在缓存内部数据如图所示:

0cab9b7ad550fa1d16436da3f604056f.png

这里我们将列表第一个节点称为头结点,最后一个节点为尾结点。

当调用缓存获取 key=1 的数据,LRU 算法需要将 1 这个节点移动到头结点,其余节点不变,如图所示。

0c9899e39165702e9486e9f51fb53ee0.png

然后我们插入一个 key=8 节点,此时缓存容量到达上限,所以加入之前需要先删除数据。由于每次查询都会将数据移动到头结点,未被查询的数据就将会下沉到尾部节点,尾部的数据就可以认为是最少被访问的数据,所以删除尾结点的数据。

421e833357742a93cca8bc5ccb39e5c7.png

然后我们直接将数据添加到头结点。

8ab6a637be1e6fdab9fdf766dc59a6be.png

这里总结一下 LRU 算法具体步骤:

新数据直接插入到列表头部

缓存数据被命中,将数据移动到列表头部

缓存已满的时候,移除列表尾部数据。

LRU 算法实现

上面例子中可以看到,LRU 算法需要添加头节点,删除尾结点。而链表添加节点/删除节点时间复杂度 O(1),非常适合当做存储缓存数据容器。但是不能使用普通的单向链表,单向链表有几点劣势:

每次获取任意节点数据,都需要从头结点遍历下去,这就导致获取节点复杂度为 O(N)。

移动中间节点到头结点,我们需要知道中间节点前一个节点的信息,单向链表就不得不再次遍历获取信息。

针对以上问题,可以结合其他数据结构解决。

使用散列表存储节点,获取节点的复杂度将会降低为 O(1)。节点移动问题可以在节点中再增加前驱指针,记录上一个节点信息,这样链表就从单向链表变成了双向链表。

综上使用双向链表加散列表结合体,数据结构如图所示:

a2eb456c3c92062b559d42381da3dca7.png

在双向链表中特意增加两个『哨兵』节点,不用来存储任何数据。使用哨兵节点,增加/删除节点的时候就可以不用考虑边界节点不存在情况,简化编程难度,降低代码复杂度。

LRU 算法实现代码如下,为了简化 key ,val 都认为 int 类型。

public class LRUCache {

Entry head, tail;

int capacity;

int size;

Map cache;

public LRUCache(int capacity) {

this.capacity = capacity;

// 初始化链表

initLinkedList();

size = 0;

cache = new HashMap<>(capacity + 2);

}

/**

* 如果节点不存在,返回 -1.如果存在,将节点移动到头结点,并返回节点的数据。

*

* @param key

* @return

*/

public int get(int key) {

Entry node = cache.get(key);

if (node == null) {

return -1;

}

// 存在移动节点

moveToHead(node);

return node.value;

}

/**

* 将节点加入到头结点,如果容量已满,将会删除尾结点

*

* @param key

* @param value

*/

public void put(int key, int value) {

Entry node = cache.get(key);

if (node != null) {

node.value = value;

moveToHead(node);

return;

}

// 不存在。先加进去,再移除尾结点

// 此时容量已满 删除尾结点

if (size == capacity) {

Entry lastNode = tail.pre;

deleteNode(lastNode);

cache.remove(lastNode.key);

size--;

}

// 加入头结点

Entry newNode = new Entry();

newNode.key = key;

newNode.value = value;

addNode(newNode);

cache.put(key, newNode);

size++;

}

private void moveToHead(Entry node) {

// 首先删除原来节点的关系

deleteNode(node);

addNode(node);

}

private void addNode(Entry node) {

head.next.pre = node;

node.next = head.next;

node.pre = head;

head.next = node;

}

private void deleteNode(Entry node) {

node.pre.next = node.next;

node.next.pre = node.pre;

}

public static class Entry {

public Entry pre;

public Entry next;

public int key;

public int value;

public Entry(int key, int value) {

this.key = key;

this.value = value;

}

public Entry() {

}

}

private void initLinkedList() {

head = new Entry();

tail = new Entry();

head.next = tail;

tail.pre = head;

}

public static void main(String[] args) {

LRUCache cache = new LRUCache(2);

cache.put(1, 1);

cache.put(2, 2);

System.out.println(cache.get(1));

cache.put(3, 3);

System.out.println(cache.get(2));

}

}

LRU 算法分析

缓存命中率是缓存系统的非常重要指标,如果缓存系统的缓存命中率过低,将会导致查询回流到数据库,导致数据库的压力升高。

结合以上分析 LRU 算法优缺点。

LRU 算法优势在于算法实现难度不大,对于对于热点数据, LRU 效率会很好。

LRU 算法劣势在于对于偶发的批量操作,比如说批量查询历史数据,就有可能使缓存中热门数据被这些历史数据替换,造成缓存污染,导致缓存命中率下降,减慢了正常数据查询。

LRU 算法改进方案

以下方案来源与 MySQL InnoDB LRU 改进算法

将链表拆分成两部分,分为热数据区,与冷数据区,如图所示。

ff55cac87af5b49c6373d39894b82385.png

改进之后算法流程将会变成下面一样:

访问数据如果位于热数据区,与之前 LRU 算法一样,移动到热数据区的头结点。

插入数据时,若缓存已满,淘汰尾结点的数据。然后将数据插入冷数据区的头结点。

处于冷数据区的数据每次被访问需要做如下判断:

若该数据已在缓存中超过指定时间,比如说 1 s,则移动到热数据区的头结点。

若该数据存在在时间小于指定的时间,则位置保持不变。

对于偶发的批量查询,数据仅仅只会落入冷数据区,然后很快就会被淘汰出去。热门数据区的数据将不会受到影响,这样就解决了 LRU 算法缓存命中率下降的问题。

其他改进方法还有 LRU-K,2Q,LIRS 算法,感兴趣同学可以自行查阅。

欢迎关注我的公众号:程序通事,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:studyidea.cn

224c5fdad649148ae4ab5f72f4a2fd5f.png

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[聊聊缓存淘汰算法-LRU 实现原理]http://www.zyiz.net/tech/detail-93930.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/441780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【qduoj】C语言_求整数各位数之和

题干&#xff1a; 描述 输入一个正整数r&#xff08;0<r<10&#xff09;&#xff0c;做r次下列运算&#xff1a;输入一个整数&#xff0c;输出它的位数及各位数之和。 输入 同上 输出 同上 输入样例 1 3 123456 -100 99 输出样例 1 number6,sum21 number3,sum1 n…

三个月计算机培训班,三个月复盘:学完两个设计软件,并开始学画画

从4月1日开始明确目标&#xff0c;到6月30日&#xff0c;整整三个月的时间&#xff0c;我一直在努力前行。其中有多次的调整&#xff0c;但整体方向不变。来梳理一下这三个月所做的事&#xff1a;4.1-5.26 完成PS学习(75课)5.27-6.26 完成CDR学习(65课)5.27 从零基础开始学习画…

mysql源码包和二进制包_Linux软件包(源码包和二进制包)

Linux下的软件包众多&#xff0c;且几乎都是经 GPL 授权、免费开源(无偿公开源代码)的。这意味着如果你具备修改软件源代码的能力&#xff0c;只要你愿意&#xff0c;可以随意修改。GPL&#xff0c;全称 General Public License&#xff0c;中文名称“通用性公开许可证”&#…

【qduoj】最长公共子串

题干&#xff1a; 描述 编写一个程序&#xff0c;求两个字符串的最长公共子串。输出两个字符串的长度&#xff0c;输出他们的最长公共子串及子串长度。如果有多个最长公共子串请输出在第一个字符串中先出现的那一个。 特别注意公共子串中可能包含有空格&#xff0c;但不计回车…

计算机导论结业报告大一,河北工业大学计算机导论结业论文.pdf

计算科学导论结业论文(黄路路 计算机科学与软件学院112班 112436)摘要 本文采用简洁的语言浅显扼要的讲解了计算机的系统理论知识&#xff0c;起抛砖引玉的作用。本文核心知识&#xff1a;共包含四大部分&#xff1a;计算理论、计算机的系统结构、信息的表示、计算科学与C语言的…

pythonjson实例_python:JSON的两种常用编解码方式实例解析

概念JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;易于人阅读和编写。在日常的工作中&#xff0c;应用范围极其广泛。这里就介绍python下它的两种编解码方法&#xff1a;使用json函数使用 JSON 函数需要导入 json 库&#xff1a;import json。函数…

caxa计算机编程,CAXA软件编程实例1

课时&#xff1a;75节课时长&#xff1a;24.1小时课级&#xff1a;中级提高课程从基础讲起&#xff0c;仅贴实际生产实践&#xff0c;适合职业院校教师、企业技术员、学生学习&#xff0c;讲解细致、全面&#xff0c;带你学习带你飞、软件使用常见问题及解决方法和使用技巧详细…

【qduoj】C语言_凯撒密码

题干&#xff1a; 描述 据说最早的密码来自于罗马的凯撒大帝。消息加密的办法是&#xff1a;对消息原文中的每个字母&#xff0c;分别用该字母之后的第5个字母替换&#xff08;例如&#xff1a;消息原文中的每个字母A都分别替换成字母F&#xff09;。而你要获得消息原文&#…

python中常用的函数有哪些_Python 最常用的语句、函数有哪些?

一、常用语句1、条件语句&#xff1a;if else一句话概括该语句作用&#xff1a;非此即彼。python中的 if else 的语句功能更加强大、更加灵活。2、循环语句&#xff1a;for & while循环语句中&#xff0c;还有两个关键字至为重要&#xff1a;continue 与 break。这两个关键…

计算机函数select,select函数

学习目标了解select函数的各参数的作用&#xff0c;能够在程序设计中正确使用select函数使用select函数&#xff0c;编写一个简单socket服务器程序&#xff0c;可支持多客户端连接1、select函数机制select函数允许程序同时在等待多个底层文件描述符输入的到达&#xff0c;并且只…

【CodeForces - 833A】The Meaningless Game(思维题,数学,可用牛顿迭代法,知识点总结)

题干&#xff1a; Slastyona and her loyal dog Pushok are playing a meaningless game that is indeed very interesting. The game consists of multiple rounds. Its rules are very simple: in each round, a natural number k is chosen. Then, the one who says (or ba…

python创建变量并赋值_python怎么给变量赋值

在学习变量及赋值之前,我们要知道什么是变量! Python语言中,用等号【=】来表示赋值,Python赋值并不是直接将一个值赋值给一个变量,在Python中,对象是通过引用传递的;在传递时,不管这个对象是新创建的还是已经存在的,都是将该对象的引用赋值给变量。 举个例子,3 * 4 =…

【CodeForces - 670D1 】Magic Powder - 1 (模拟 或 枚举 或二分优化)

题干&#xff1a; This problem is given in two versions that differ only by constraints. If you can solve this problem in large constraints, then you can just write a single solution to the both versions. If you find the problem too difficult in large cons…

第二课计算机ppt,第二课计算机系统.ppt

第二课计算机系统主要部件功能及参数指标 机 箱 外 壳 一个完整的计算机系统是由硬件(Hardware)系统和软件(Software)系统两大部分组成。 计算机硬件是指系统中可触摸得到的设备实体&#xff0c;是计算机工作的基础。 计算机软件是指在硬件设备上运行的各种程序和文档。 软件系…

正则表达式 python_Python正则表达式总结

之前我们讲解了 正则表达式 的起源、发展、流派、语法、引擎、优化等相关知识&#xff0c;今天我们主要来学习一下 正则表达式在 Python语言 中的应用&#xff01;大多数编程语言的正则表达式设计都师从Perl&#xff0c;所以语法基本相似&#xff0c;不同的是每种语言都有自己的…

建立远程ftp服务器,利用无线路由器建立FTP服务器

路由器的应用非常广泛&#xff0c;无线路由器技术也更加的完善和稳定&#xff0c;利用无线路由器能构建FTP服务器。下面&#xff0c;我就具体的方法在这里拿出来和大家分享一下&#xff0c;希望对大家有用。一、FTPFTP(文件传输协议)诞生之后&#xff0c;便迅速地得到了推广和应…

【HDU - 5912】Fraction (模拟)

题干&#xff1a; Mr. Frog recently studied how to add two fractions up, and he came up with an evil idea to trouble you by asking you to calculate the result of the formula below: As a talent, can you figure out the answer correctly? Input The first …

vue mysql webapp_基于Laravel+VueJS实战开发WebAPP

资源介绍【课程内容】1-git库与开发环境及工具软件介绍2-安装laravel框架3-安装laravel-ide-helper增强代码提示4-配置数据库与使用migrations创建表5-解决mysql5.7以下laravel不能执行数据迁移的问题6-合理的路由布局与分组路由7-远程开发环境服务器搭建与虚拟面板的使用8-使用…

计算机测试怎么提交,Win7电脑怎么测试上传速度?

做网站的人都知道上传速度是很重要的&#xff0c;因为太差的上传速度会影响工作的进度&#xff0c;所以他们经常要对上传速度进行测试&#xff0c;但是有一些新手不知道Win7电脑怎么测试上传速度&#xff1f;为此小编赶紧整理了以下教程&#xff0c;不知道的朋友赶紧来看看吧&a…

【HDU - 5914 】Triangle (打表 或 set维护)

题干&#xff1a; Mr. Frog has n sticks, whose lengths are 1,2, 3⋯⋯n respectively. Wallice is a bad man, so he does not want Mr. Frog to form a triangle with three of the sticks here. He decides to steal some sticks! Output the minimal number of sticks h…