失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > java cache缓存_Redis缓存失效策略思考

java cache缓存_Redis缓存失效策略思考

时间:2024-09-23 21:44:22

相关推荐

java cache缓存_Redis缓存失效策略思考

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 cache; public LRUCache(int capacity) {this.capacity = capacity; this.cache = new LinkedList<>(); } /** * 获取缓存元素 * * 找到元素后将元素从原位置删除并插入到链表头部(最近) */ public CacheElement get(String key) {Iterator 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 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 cache缓存_Redis缓存失效策略思考》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。