LRU算法在服务端和操作系统中的应用
Posted 我们的开心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LRU算法在服务端和操作系统中的应用相关的知识,希望对你有一定的参考价值。
文/汪栋
首先来看一个业务场景,某公司希望能建一个用户系统,给不同的业务系统提供用户的信息。由于业务系统访问用户信息的频率特别高,因此该用户系统在设计的时候需要考虑性能问题。


用户的信息需要存储在数据库中,考虑到要提高系统的性能,我们很容易想到在内存中建一个哈希表,每次请求用户信息,首先在内存的哈希表中查找用户。当哈希表中存在所请求的用户信息时,直接返回给业务系统,如果不存在,则去数据库中查找,并将该用户插入到哈希表。由于内存的访问速度远快于数据库(存储在磁盘中)的访问速度,因此这种设计可以提高系统的性能。

然而当这样的用户系统上线后,开发工程师满以为可以怀着新系统上线的成就感,享受接下来的闲适了,没想到过了一段时间后,线上服务器宕机了。原来随着用户信息的增多,内存中的哈希表被撑爆了,导致内存溢出,这时只有重启服务器了…
工程师告诉老板,想避免这样的困境,只有再多加几台服务器了,然而公司为了节省成本,不愿意增加服务器。另一方面,增加服务器并不能从根本上解决问题,后续还是会面临内存不够用的情况。经过仔细分析后,工程师想到当内存快消耗完的时候,就随机移除哈希表中一半的用户。但是,另一个问题来了,如果高频访问的用户被移除,系统性能就会降低,该怎么权衡这个问题呢?这时,LRU(Least Recently Used)算法闪亮登场了,注意啦,LRU可不是URL。
LRU是内存管理的一种页面置换算法,因此最早是在操作系统的内存管理中使用。该算法的核心是,将最近最少使用的页面置换出内存,以调入新访问的页面。LRU算法能够提高系统性能,是基于计算机中著名的局部性原理,即在前几条指令中被频繁使用的页面,很可能在后面的几条指令中被使用。比内存速度还快的cache就是基于局部性原理设计的。
在上面的用户系统中,就可以在服务端的哈希表上使用LRU算法,当哈希表满了后,需要插入新的用户时,就将哈希表中最少访问的用户给置换出来。我们知道,哈希表是由“Key-Value”组成,不存在具有规律的排列顺序,那么我们怎么将最近最少访问的数据给选出来呢?这时有以下两种方案:
1
为了能够每次找到访问频率最小的那个“Key-Value”,在内存中维护一张表(数组存储),记录每个“Key”对应的访问频率。但这种方案的缺点是:每次需要从哈希表中置换出一个用户信息时,需要遍历数组,找到访问频率最低的“Key”,且每次访问哈希表,均需要遍历数组找到对应的“Key”更新其频率。虽然内存访问速度快,但这种方案明显系统开销较大。

2


在Eclipse中通过java程序来实现采用LRU算法的用户系统,然后采用多线程的方式模拟多个用户对用户系统的访问。左图是不采用LRU算法时的用户系统的访问测试运行结果,右图是采用LRU算法的用户系统的访问测试运行结果。两图的数据取得的条件为:内存哈希表容量是200条,数据库总记录为1000条,高频用户为100个,每次访问是高频用户的概率是0.8,通过5个线程模拟五个访问用户系统的业务系统,每个线程持续访问10000次。


可以看到LRU算法能够明显增加访问用户系统的内存命中率(内存命中次数越高,访问数据库次数越低),增强系统性能。为了更加直观的对比采用LRU算法前后的用户系统的性能,将10000次的访问性能数据写入txt文本,用Matlab读入该数据文本,作出了性能对比图,如下图所示。

定义的哈希链表中的节点类,包含“Key,Value”结构,一个指向前向节点的指针和一个指向后向节点的指针。


访问用户系统的接口函数,由于该过程同时存在读操作和写操作,读和写、写和写存在互斥,在不同线程中同时执行,因此采用了synchronized上锁。根据要访问的数据是否存在于哈希表中,对哈希表执行相应的插入操作和更新操作。


更新哈希表的操作,通过修改指针域,将最近一次访问的用户数据移到哈希链表的头部。


将最近访问的不存在于哈希表中的数据,插入到哈希表的头部,如果哈希表容量已满,需要删除哈希表尾部的元素(最近最少访问的数据)。


实现Runnable接口后,重写的run方法。
本文实现LRU算法的完整程序代码通过以下百度网盘链接分享(永久有效),有兴趣的朋友可以查阅,欢迎大家批评指正。

参考文献:
[1]. Andrew S.Tanenbaum, Herbert Bos著, 陈向群译.现代操作系统[M], 机械工业出版社.
[2].https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU).

https://pan.baidu.com/s/1LLKHeyNogJbtk4jOThf5jg
作者简介
汪栋,来自成都研发部,热爱算法的攻城狮一枚,追求“将工作变为开心,将开心融入工作”。喜欢学习并享受编程实现各种算法的成就感,CSDN技术博客名wangdong_001。
轮值总编:杨贤文
责任编辑:谭景
美编:来丽晗
技术支持:刘津津
我们的开心 · 总编辑部
(成 研)
■欢迎来稿:请按“作品名-作者-部门”命名,发送到abckx@abchina.com
以上是关于LRU算法在服务端和操作系统中的应用的主要内容,如果未能解决你的问题,请参考以下文章