Redis进阶-Redis缓存优化

简介: Redis进阶-Redis缓存优化


缓存穿透

定义

查询一个根本不存在的数据, 缓存和DB都不会命中, 白嫖了缓存层和DB 。 通常出于容错的考虑, 如果从存储层查不到数据则不写入缓存层。

缓存穿透将导致不存在的数据每次请求都要到存储层去查询, 失去了缓存保护后端存储的意义。


原因

通常缓存穿透的原因如下:

  • 自身业务代码或者数据出现问题。
  • 恶意攻击、 爬虫等造成大量空命中

缓存穿透问题解决方案

缓存空对象

这个也很好理解,需要注意的是对空对象,设置个过期时间,伪代码如下

String get(String key) {
  // 从缓存中获取数据
  String cacheValue = cache.get(key)
  // 缓存为空
  if (StringUtils.isBlank(cacheValue)) {
   // 从存储中获取
   String storageValue = storage.get(key);
   cache.set(key, storageValue);
   // 如果存储数据为空, 需要设置一个过期时间(300秒)
  if (storageValue == null) {
    cache.expire(key, 60 * 5);
   }
   return storageValue;
 } else {
   // 缓存非空
   return cacheValue;
 } 
}

一般也够用了,极限情况:恶意攻击,几千万个不存在的id , 都打到了DB,你也都对这几千万个id 作为key, 存到了redis , 虽然他们的value都是空,而且你也设置了过期时间。

但是你想一下,你这几千万次的DB查询,你也挺难过吧,并且你redis里缓存这几千万个key , 那宝贵的内存资源岂不是白白的浪费掉了。。。。。

所以你需要布隆过滤器

看场景,取舍。


布隆过滤器

Redis进阶-布隆过滤器


缓存同时失效

由于大批量缓存在同一时间失效可能导致大量请求同时穿透缓存直达数据库,可能会造成数据库瞬间压力过大甚至挂掉。

缓存同时失效解决方案

对于这种情况我们在批量增加缓存时最好将这一批数据的缓存过期时间设置为一个时间段内的不同时间 。 比如 5到10分钟之间的一个随机时间。

伪代码如下

String get(String key) {
  // 从缓存中获取数据
  String cacheValue = cache.get(key);
  // 缓存为空
  if (StringUtils.isBlank(cacheValue)) {
    // 从存储中获取
    String storageValue = storage.get(key);
    cache.set(key, storageValue);
     //设置一个过期时间(300到600之间的一个随机数)
    int expireTime = new Random().nextInt(300) + 300;
    if (storageValue == null) {
      cache.expire(key, expireTime);
    }
    return storageValue;
  } else {
    // 缓存非空
    return cacheValue;
  }
}

缓存雪崩

缓存雪崩指的是缓存层支撑不住或宕掉后, 流量会像奔逃的野牛一样, 打向后端存储层.

由于缓存层承载着大量请求, 有效地保护了存储层, 但是如果缓存层由于某些原因不能提供服务(比如超大并发过来,缓存层支撑不住,或者由于缓存设计不好,类似大量请求访问bigkey,导致缓存能支撑的并发急剧下降), 于是大量请求都会达到存储层, 存储层的调用量会暴增, 造成存储层也会级联宕机的情况。


缓存雪崩的解决方案

预防和解决缓存雪崩问题, 可以从以下三个方面进行着手。

  • 1) 保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。
  • 2) 依赖隔离组件为后端限流并降级。比如使用Hystrix限流降级组件。
  • 3) 提前演练。 在项目上线前, 演练缓存层宕掉后, 应用以及后端的负载情况以及可能出现的问题, 在此基础上做一些预案设定。

缓存击穿 ( 热点缓存key重建优化 )

一般情况下,我们使用“缓存+过期时间”的策略既可以加速数据读写, 又保证数据的定期更新, 这种模式基本能够满足绝大部分需求。

但是有两个问题如果同时出现, 可能就会对应用造成致命的危害:

  • 当前key是一个热点key(例如一个热门的娱乐新闻),并发量非常大
  • 重建缓存不能在短时间完成, 可能是一个复杂计算, 例如复杂的SQL、 多次IO、 多个依赖等。

在缓存失效的瞬间, 有大量线程来重建缓存, 造成后端负载加大, 甚至可能会让应用崩溃 。

再通俗一点来说 :对于一些设置了过期时间的key,假设这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。 如果正好在高并发的时候,这个key过期了。。。。 大量的请求都打到了DB层,造成DB的负载非常大,甚至宕机。

缓存击穿的解决方案 (热点缓存key重建优化)

要解决这个问题主要就是要避免大量线程同时重建缓存。

我们可以利用互斥锁来解决,此方法只允许一个线程重建缓存, 其他线程等待重建缓存的线程执行完, 重新从缓存获取数据即可。

伪代码如下

String get(String key) {
  // 从Redis中获取数据
  String value = redis.get(key);
  // 如果value为空, 则开始重构缓存
  if (value == null) {
    // 只允许一个线程重建缓存, 使用nx, 并设置过期时间ex
    String mutexKey = "mutext:key:" + key;
    if (redis.set(mutexKey, "1", "ex 180", "nx")) {
    // 从数据源获取数据
    value = db.get(key);
    // 回写Redis, 并设置过期时间
    redis.setex(key, timeout, value);13 // 删除key_mutex
    redis.delete(mutexKey);
    }// 其他线程休息50毫秒后重试
    else {
      Thread.sleep(50);
      get(key);
    }
  }
  return value;
}


相关文章
|
3月前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。
|
4月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
231 1
Redis专题-实战篇二-商户查询缓存
|
3月前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。
|
4月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
687 5
|
4月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
8月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
8月前
|
缓存 NoSQL Java
Redis+Caffeine构建高性能二级缓存
大家好,我是摘星。今天为大家带来的是Redis+Caffeine构建高性能二级缓存,废话不多说直接开始~
1131 0
|
8月前
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
271 32
|
8月前
|
缓存 NoSQL Java
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
222 5
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
|
10月前
|
缓存 NoSQL Java
Redis应用—8.相关的缓存框架
本文介绍了Ehcache和Guava Cache两个缓存框架及其使用方法,以及如何自定义缓存。主要内容包括:Ehcache缓存框架、Guava Cache缓存框架、自定义缓存。总结:Ehcache适合用作本地缓存或与Redis结合使用,Guava Cache则提供了更灵活的缓存管理和更高的并发性能。自定义缓存可以根据具体需求选择不同的数据结构和引用类型来实现特定的缓存策略。
631 16
Redis应用—8.相关的缓存框架