分布式缓存

文章目录

  • 前言
    • 分布式缓存
      • 1、缓存雪崩
      • 2、缓存穿透
      • 3、缓存预热
      • 4、缓存更新
      • 5、缓存降级

前言

  如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
  而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


分布式缓存

序号 缓存问题
1 缓存雪崩
2 缓存穿透
3 缓存预热
4 缓存更新
5 缓存降级

1、缓存雪崩

【缓存雪崩】是由于原有缓存失效(过期),新缓存未到期间。所有请求都去查询数据库,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。

解决思路:

达到每个缓存的过期时间重复率降低的目的或者制造延迟过期时间的行为,最终防止集体失效的事件。

解决方案:

第一种解决方案:

为 key 设置不同的缓存失效时间,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

第二种解决方案:

给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存(另起线程),实例伪代码如下:

//伪代码
public object GetProductListNew() {
     
  int cacheTime = 30;
  String cacheKey = "test_list";
  //缓存标记_sign
  String cacheSign = cacheKey + "_sign";
  String sign = CacheHelper.Get(cacheSign);

  //获取缓存值
  String cacheValue = CacheHelper.Get(cacheKey);
  if (sign != null) {
     
    return cacheValue; //未过期,直接返回
  } else {
     
  CacheHelper.Add(cacheSign, "1", cacheTime);
  ThreadPool.QueueUserWorkItem((arg) -> {
     
    //这里一般是 sql查询数据
    cacheValue = GetProductListFromDB();
    //日期设缓存时间的2倍,用于脏读
    CacheHelper.Add(cacheKey, cacheValue, cacheTime * 2);
  });
  return cacheValue;
}

说明:

  1. 缓存标记:记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际key的缓存;
  2. 缓存数据:它的过期时间比缓存标记的时间延长1倍,例:标记缓存时间30分钟,数据缓存设置为60分钟。 这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存

2、缓存穿透

缓存穿透指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在 缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请 求就绕过缓存直接查数据库,这也是经常提的【缓存命中率】问题。

解决方案:

如果一个查询返回的数据为空(不管是数据不 存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟,通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。


3、缓存预热

缓存预热就是系统上线后,将【相关的缓存数据】直接加载到缓存系统,这样就可以避免在用户请求的时候, 先查询数据库,然后再将数据缓存的问题!

解决方案:

  • 数据量不大的情况,项目启动后自动加载;
  • 数据量大的情况下,可以定时加载;
  • 人为 设计一个缓存加载web功能;

4、缓存更新

缓存更新除了缓存服务器自带的缓存失效策略之外(Redis 默认的有 6 中策略可供选择),我们还可以 根据具体的业务需求进行自定义的缓存淘汰

  • 定时去清理过期的缓存;
  • 当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数 据并更新缓存。

两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂!具体用哪种方案,大家可以根据自己的应用场景来权衡。


5、缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级

降级的目的:

保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。
在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:

  • 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
  • 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;
  • 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;
  • 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。

参考:

https://blog.csdn.net/xlgen157387/article/details/79530877

你可能感兴趣的:(noSql,java,redis,缓存)