公众号IT徐胖子原创本文,请勿转载
1 删除过期数据
我们设置Redis元素时可以指定过期时间,那么Redis如何删除这些超时元素?Redis采用了两种策略:定期删除和惰性删除。
(1) 定期删除
Redis每隔一段时间就检查哪些KEY已经过期,如果过期就删除。但是我们来设想一个问题:如果Redis存储KEY非常多,仅仅超时检查这项工作就会非常耗费资源并严重影响服务能力。为了解决这个问题Redis并不是检查全量KEY而只是检查部分,同时引入了惰性删除策略。
(2) 惰性删除
假设当KEY1已经过期,但是由于没有被检查到而未被删除。那么当程序访问KEY1时,Redis会检查KEY1是否过期,如果过期则删除并不返回该值,这就是惰性删除策略。结合定期删除和惰性删除两种策略,就可以保证过期数据可以被删除。
2 内存淘汰
当内存不足时Redis会选择一些缓存元素进行删除,那么哪些元素会被删除?常见内存淘汰策略如下:
no-enviction
禁止驱逐数据,新写入操作会报错
volatile-lru
从已设置过期时间的数据集选择最近最少使用的数据淘汰
volatile-ttl
从已设置过期时间的数据集选择将要过期的数据淘汰
volatile-random
从已设置过期时间的数据集选择任意的数据淘汰
allkeys-lru
从数据集选择最近最少使用的数据淘汰
allkeys-random
从数据集选择任意的数据淘汰
复制
LRU(Least Recently Used)最近最少使用是比较常用的策略,我们使用JAVA代码实现一个简单LRU策略,代码原理并不复杂:使用一个链表存储元素,表头存储最近访问的元素,这样存储的结果是表尾存储最早访问的元素,表头存储最近访问的元素,当超出链表容量时删除表尾元素即可。
/**
* 元素对象
*
* @author 微信公众号「IT徐胖子」
*
*/
public class CacheElement {
private String key;
private Object value;
public CacheElement(String key, Object value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public Object getValue() {
return value;
}
@Override
public String toString() {
return "Element [key=" + key + ", value=" + value + "]";
}
}
/**
* LRU缓存策略
*
* @author 微信公众号「IT徐胖子」
*
*/
public class LRUCache {
private int capacity;
private LinkedList<CacheElement> cache;
public LRUCache(int capacity) {
this.capacity = capacity;
this.cache = new LinkedList<>();
}
/**
* 获取缓存元素
*
* 找到元素后将元素从原位置删除并插入到链表头部(最近)
*/
public CacheElement get(String key) {
Iterator<CacheElement> iterator = cache.iterator();
while (iterator.hasNext()) {
CacheElement element = iterator.next();
if (element.getKey().equals(key)) {
iterator.remove();
System.out.println("获取到元素=" + element);
put(element.getKey(), element.getValue());
return element;
}
}
return null;
}
/**
* 存储缓存元素
*
* 新元素插入到链表头部(最近)
*/
public boolean put(String key, Object value) {
Iterator<CacheElement> iterator = cache.iterator();
while (iterator.hasNext()) {
CacheElement element = iterator.next();
if (element.getKey().equals(key)) {
iterator.remove();
break;
}
}
if (capacity == cache.size()) {
CacheElement deleteElement = cache.removeLast();
System.out.println("容量已满删除尾部元素=" + deleteElement);
}
CacheElement element = new CacheElement(key, value);
cache.addFirst(element);
System.out.println("插入头部元素=" + element);
return Boolean.TRUE;
}
@Override
public String toString() {
return "LRUCache [capacity=" + capacity + ", cache=" + cache + "]";
}
}
/**
* LRU测试实例
*
* @author 微信公众号「IT徐胖子」
*
*/
public class TestCache {
public static void main(String[] args) {
System.out.println("==================存储缓存元素==================");
LRUCache cache = new LRUCache(2);
CacheElement element0 = new CacheElement("k0", "v0");
CacheElement element1 = new CacheElement("k1", "v1");
CacheElement element2 = new CacheElement("k2", "v2");
cache.put(element0.getKey(), element0.getValue());
cache.put(element1.getKey(), element1.getValue());
cache.put(element2.getKey(), element2.getValue());
System.out.println("==================获取缓存元素==================");
System.out.println("获取元素之前缓存对象=" + cache);
cache.get("k1");
System.out.println("获取元素之后缓存对象=" + cache);
}
}
==================存储缓存元素==================
插入头部元素=Element [key=k0, value=v0]
插入头部元素=Element [key=k1, value=v1]
容量已满删除尾部元素=Element [key=k0, value=v0]
插入头部元素=Element [key=k2, value=v2]
==================获取缓存元素==================
获取元素之前缓存对象=LRUCache [capacity=2, cache=[Element [key=k2, value=v2], Element [key=k1, value=v1]]]
获取到元素=Element [key=k1, value=v1]
插入头部元素=Element [key=k1, value=v1]
获取元素之后缓存对象=LRUCache [capacity=2, cache=[Element [key=k1, value=v1], Element [key=k2, value=v2]]]
复制
3 文章总结
本文分析了Redis缓存失效策略:删除过期数据和内存淘汰,并且使用JAVA代码模拟了LRU策略实现。
这里我们可以做一个展开:Redis分布式锁是否可靠。因为Redis存在内存淘汰机制,那么作为分布式锁的KEY概率上会被淘汰,从而导致分布式锁失效。所以仅仅有分布式锁是不够的,我们还需要其它方法,例如设置数据库层唯一索引,防止重复数据产生。
长按二维码关注更多精彩文章
文章转载自JAVA前线,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
Redis 8.0:开启一体化多功能开源数据平台新时代
老王两点中
145次阅读
2025-05-12 09:00:43
Redis 挂 AGPLv3 “战袍”,开源江湖风云突变
青年数据库学习互助会
77次阅读
2025-05-08 10:04:49
Redis改协议内幕曝光!核心开发者亲述被“踢出局”,外部贡献者几乎全跑光了!
老鱼笔记
51次阅读
2025-04-17 10:41:56
Redis数据库——Cluster集群模式
编程Cookbook
50次阅读
2025-04-16 15:34:44
亚马逊:MemoryDB,一款内存优先的云数据库
数据库应用创新实验室
37次阅读
2025-04-18 09:54:15
redis初识
chirpyli
35次阅读
2025-05-07 17:32:31
优雅遍历和删除特定开头的key
陌殇流苏
30次阅读
2025-04-25 12:17:03
Redis学习笔记
chirpyli
17次阅读
2025-05-13 15:40:30
Redis数据库——持久化机制
编程Cookbook
16次阅读
2025-04-15 11:32:38
Redis内存溢出故障排查
IT那活儿
14次阅读
2025-04-25 10:10:09