首页 存档 技术 查看内容

由浅入深介绍 Redis LRU 策略的具体实现

2018-3-30 13:00 |来自: 互联网 581 0

摘要: 点击上方“蓝字”可以关注我们哦 |本文来自:chinaunix博客 |作者:zxszcaijin |原文链接:http://blog.chinaunix.net/uid-20708886-id-5753422.html 在使用redis作为缓存的场景下,内存淘汰策略决定的redis的内存 ...

点击上方“蓝字”可以关注我们哦




|本文来自:chinaunix博客

|作者:zxszcaijin

|原文链接:http://blog.chinaunix.net/uid-20708886-id-5753422.html



在使用redis作为缓存的场景下,内存淘汰策略决定的redis的内存使用效率。在大部分场景下,我们会采用LRU(Least Recently Used)来作为redis的淘汰策略。本文将由浅入深的介绍redislru策略的具体实现。


首先我们来科普下,什么是LRU ?(以下来自维基百科)

Discards the least recently used items first. This algorithm requires keeping track of what was used when, which is expensive if one wants to make sure the algorithm always discards the least recently used item. General implementations of this technique require keeping “age bits” for cache-lines and track the “Least Recently Used” cache-linebased on age-bits. In such an implementation, every time a cache-line is used, the age of all other cache-lines changes.


简而言之,就是每次淘汰最近最少使用的元素。一般的实现,都是采用对存储在内存的元素采用‘agebits’来标记该元素从上次访问到现在为止的时长,从而在每次用LRU淘汰时,淘汰这些最长时间未被访问的元素。


这里我们先实现一个简单的LRUCache,以便于后续内容的理解 。(来自leetcod,不过这里我重新用Python语言实现了)


实现该缓存满足如下两点


1、get(key) 如果该元素(总是正数)存在,将该元素移动到lru头部,并返回该元素的值,否则返回-1。


2、set(key,value) 设置一个key的值为value(如果该元素存在),并将该元素移动到LRU头部。否则插入一个key,且值为value。如果在设置前检查到,该key插入后,会超过cache的容量,则根据LRU策略,删除最近最少使用的key。


分析


这里我们采用双向链表来实现元素(k-v键值对)的存储,同时采用hash表来存储相关的key与item的对应关系。这样,我们既能在O(1)的时间对key进行操作,同时又能利用DoubleLinkedList的添加和删除节点的便利性。(get/set都能在O(1)内完成)。

具体实现(Python语言)


class Node:

key=None

value=None

pre=None

next=None

def __init__(self,key,value):

self.key=key

self.value=value

class LRUCache:

capacity=0

map={} # key is string ,and value is Node object

head=None

end=None

def __init__(self,capacity):

self.capacity=capacity

def get(self,key):

if key in self.map:

node=self.map[key]

self.remove(node)

self.setHead(node)

return node.value

else:

return -1

def getAllKeys(self):

tmpNode=None

if self.head:

tmpNode=self.head

while tmpNode:

print (tmpNode.key,tmpNode.value)

tmpNode=tmpNode.next

def remove(self,n):

if n.pre:

n.pre.next=n.next

else:

self.head=n.next

if n.next:

n.next.pre=n.pre

else:

self.end=n.pre

def setHead(self,n):

n.next=self.head

n.pre=None

if self.head:

self.head.pre=n

self.head=n

if not self.end:

self.end=self.head

def set(self,key,value):

if key in self.map:

oldNode=self.map[key]

oldNode.value=value

self.remove(oldNode)

self.setHead(oldNode)

else:

node=Node(key,value)

if len(self.map)

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部