使用 Python 的 OrderedDict(双向链表 + 字典) 来实现一个简单的 LRU 算法:
from collections import OrderedDictclass LRUDict(OrderedDict): def __init__(self, capacity): self.capacity = capacity self.items = OrderedDict() def __setitem__(self, key, value): old_value = self.items.get(key) if old_value is not None: self.items.pop(key) self.items[key] = value elif len(self.items) < self.capacity: self.items[key] = value else: self.items.popitem(last=True) self.items[key] = value def __getitem__(self, key): value = self.items.get(key) if value is not None: self.items.pop(key) self.items[key] = value return value def __repr__(self): return repr(self.items)d = LRUDict(10)for i in range(15): d[i] = iprint d近似 LRU 算法Redis 使用的并不是完全 LRU 算法 。不使用 LRU 算法,是为了节省内存,Redis 采用的是随机LRU算法,Redis 为每一个 key 增加了一个24 bit的字段,用来记录这个 key 最后一次被访问的时间戳 。注意 Redis 的 LRU 淘汰策略是懒惰处理,也就是不会主动执行淘汰策略,当 Redis 执行写操作时,发现内存超出 maxmemory,就会执行 LRU 淘汰算法 。这个算法就是随机采样出5(默认值)个 key,然后移除最旧的 key,如果移除后内存还是超出 maxmemory,那就继续随机采样淘汰,直到内存低于 maxmemory 为止 。
如何采样就是看 maxmemory-policy 的配置,如果是 allkeys 就是从所有的 key 字典中随机,如果是 volatile 就从带过期时间的 key 字典中随机 。每次采样多少个 key 看的是 maxmemory_samples 的配置,默认为 5 。
LFURedis 4.0 里引入了一个新的淘汰策略 —— LFU(Least Frequently Used) 模式,作者认为它比 LRU 更加优秀 。
LFU 表示按最近的访问频率进行淘汰,它比 LRU 更加精准地表示了一个 key 被访问的热度 。
如果一个 key 长时间不被访问,只是刚刚偶然被用户访问了一下,那么在使用 LRU 算法下它是不容易被淘汰的,因为 LRU 算法认为当前这个 key 是很热的 。而 LFU 是需要追踪最近一段时间的访问频率,如果某个 key 只是偶然被访问一次是不足以变得很热的,它需要在近期一段时间内被访问很多次才有机会被认为很热 。
【谈谈 Redis 的过期策略】Redis 对象的热度
Redis 的所有对象结构头中都有一个 24bit 的字段,这个字段用来记录对象的热度 。
// redis 的对象头typedef struct redisObject { unsigned type:4; // 对象类型如 zset/set/hash 等等 unsigned encoding:4; // 对象编码如 ziplist/intset/skiplist 等等 unsigned lru:24; // 对象的「热度」 int refcount; // 引用计数 void *ptr; // 对象的 body} robj;
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 梦见一些妖魔鬼怪的梦是什么征兆 梦到妖魔鬼怪是什么意思?
- 梦见青色的虫子是什么 梦到很多青虫预示着什么
- 从报文交互看Telnet协议的安全系数
- 蜂蜜柠檬美人茶的做法,柠檬橙子茶的做法
- 福建茉莉花茶,茉莉花茶的选购观其形
- 百万级MySQL的数据量,该如何快速的完成数据迁移?
- 古六大茶山概况,古六大茶山之莽枝茶山的地理渊源
- 求N以内所有质数的算法及优化
- 凤凰水仙茶的采摘技巧,凤凰水仙的等级分类
- 枸杞泡水如何喝,红枣枸杞泡茶喝的功效
