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缓存失效策略思考相关推荐

  1. Redis缓存失效策略思考

    1 删除过期数据 我们设置Redis元素时可以指定过期时间,那么Redis如何删除这些超时元素?Redis采用了两种策略:定期删除和惰性删除. (1) 定期删除 Redis每隔一段时间就检查哪些KEY ...

  2. redis 查询缓存_Redis缓存总结:淘汰机制、缓存雪崩、数据不一致....

    在实际的工作项目中, 缓存成为高并发.高性能架构的关键组件 ,那么Redis为什么可以作为缓存使用呢?首先可以作为缓存的两个主要特征: 在分层系统中处于内存/CPU具有访问性能良好, 缓存数据饱和,有 ...

  3. mysql大数据更新缓存_redis缓存mysql

    Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合).这些数据类 ...

  4. java cache详解,Java内存缓存详解

    1.缓存为什么要存在 应用服务器资源是有限的,数据库每秒中接受请求的次数也是有限的.如果利用有限的资源来提供尽可能大的吞吐量呢,一个办法:减少计 算量,缩短请求流程(减少网络io或者硬盘io),这时候 ...

  5. 从Java视角理解CPU缓存(CPU Cache)

    http://coderplay.iteye.com/blog/1485760 众所周知, CPU是计算机的大脑, 它负责执行程序的指令; 内存负责存数据, 包括程序自身数据. 同样大家都知道, 内存 ...

  6. java 项目做多级缓存_【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)...

    一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...

  7. java+cache使用方法_java相关:springboot使用GuavaCache做简单缓存处理的方法

    java相关:springboot使用GuavaCache做简单缓存处理的方法 发布于 2020-3-29| 复制链接 摘记: 问题背景 实际项目碰到一个上游服务商接口有10秒的查询限制(同个账号). ...

  8. java cache教程_Java 中常用缓存Cache机制的实现

    缓存主要可分为二大类: 一.通过文件缓存,顾名思义文件缓存是指把数据存储在磁盘上,不管你是以XML格式,序列化文件DAT格式还是其它文件格式: 二.内存缓存,也就是实现一个类中静态Map,对这个Map ...

  9. ASP.NET缓存中Cache过期的三种策略

    ASP.NET缓存中Cache过期的三种策略 原文:ASP.NET缓存中Cache过期的三种策略 我们在页面上添加三个按钮并双击按钮创建事件处理方法,三个按钮使用不同的过期策略添加ASP.NET缓存. ...

最新文章

  1. 残差复合正态分布的重要性
  2. android自定义滑块解锁,android 滑动解锁
  3. Propel项目改为基于TensorFlow.js
  4. 解决ModuleNotFoundError: No module named ‘numpy.core._multiarray_umath‘ 错误
  5. 关于.h .lib .dll的总结
  6. spring 通过编程来获取属性文件
  7. python 导入模块中的命令
  8. [蓝桥杯][算法训练VIP]接水问题(思维)
  9. Java手撕Linkedlist(双向链表)基本用法的实现
  10. 【dfs】【hash】有趣的英语角(2015特长生 T2/luogu 1019)
  11. json数据转换成表格_电子表格会让您失望吗? 将行数据转换为JSON树很容易。
  12. 6410的系统时钟设置(下)---几个常用函数的C源码
  13. XSS(跨站脚本攻击)漏洞解决方案
  14. fastjson版本_Fastjson高危漏洞风险提示
  15. 天锐绿盾加密软件常见问题解决方案
  16. HP Smart 未找到扫描仪
  17. Ubuntu过去十年的10个关键时刻
  18. CAD2016入门教程
  19. zsh:command not found:conda的解决方法
  20. java中的圈复杂度计算_[代码质量] 圈复杂度和代码质量优化(附带示例代码纠正代码质量)...

热门文章

  1. mine layer(2008 World Final C)
  2. GoLand 快速入门教程
  3. Silverlight安装相关问题
  4. JAVA中“:”的用法详解
  5. Mongoose多数据库连接及实用样例
  6. Spring中为什么要开启注解扫描
  7. [洛谷P3807]【模板】卢卡斯定理
  8. Could not create local repository at /home/yizhenn/.m、IDEA倒入maven项目无法导报问题
  9. 5.2.1.开启驱动开发之路
  10. Java集合框架使用总结