缓存与Redis
Kang Lv3

缓存穿透

在请求数据时,在缓存和DB中都没有找到符合要求的数据,比如查找id为-1的请求

原因:查询某个 Key 对应的数据时,Redis 缓存中没有对应的数据,接下来到数据库中查询,然而数据库中也不存在要查询的数据,数据库会返回空,而 Redis 也不会缓存这个空结果。这就造成每次通过这样的 Key 去查询数据都会直接到数据库中查询,Redis 不会缓存空结果。这就造成了缓存穿透的问题。

解决方法

  1. 参数校验,一些不合法的参数请求直接抛出异常。比如查询的邮箱或手机号格式不对,查询数据库id小于0;
  2. 缓存无效Key,当第一次从数据库中查询出来的结果为空时,我们就将这个空对象加载到缓存,并设置合理的过期时间,如1分钟。但是如果同一时间请求了大量不同的无效Key时,Redis就会缓存大量无效的Key;
  3. 使用布隆过滤器,布隆过滤器可以针对大数据量的、有规律的键值进行处理。一条记录是不是存在,本质上是一个 Bool 值,只需要使用 1bit 就可以存储。首先经过布隆过滤器判断是否存在该值,,存在的话,再去走之后的操作。

缓存击穿/雪崩

缓存击穿:当热点数据 key 从缓存中失效时,大量访问同时请求这个数据,此时数据库层的负载压力会骤增,这种现象称为”缓存击穿”

缓存雪崩,当 Redis 中大量的 key 几乎同时过期,然后大量并发查询穿过redis击打到底层数据库上,此时数据库层的负载压力会骤增,这种现象称为”缓存雪崩”

解决方法

  • 缓存击穿
    1. 延长过期时间或永不过期。
    2. 利用互斥锁保证同一时刻只有一个客户端可以查询底层数据库的这个数据,一旦查到数据就缓存至 Redis 内,避免其他大量请求同时穿过 Redis 访问底层数据库;
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      public String getKey(String Key) {
      String result = getDataFromRedis(key);

      if (result == null) {
      if (reenLock.tryLock()) {
      result = getDataFromMysql(key);
      if (result != null) setDataToCache(key, result);
      reenLock.unlock();
      } else {
      Thread.sleep(100);
      result.getData(key);
      }
      }
      return result;
      }
  • 缓存雪崩
    1. 在一定范围内随机设置 key 的过期时间,分散 key 的过期时间,以防止大量的 key 在同一时刻过期;
    2. 对于一定要在固定时间让key失效的场景(例如每日12点准时更新所有最新排名),可以在固定的失效时间时在接口服务端设置随机延时,将请求的时间打散,让一部分查询先将数据缓存起来;
    3. Redis 缓存不可用导致热点失效,采用 Redis 集群。
  • 本文标题:缓存与Redis
  • 本文作者:Kang
  • 创建时间:2022-03-04 12:27:18
  • 本文链接:ykhou.github.io2022/03/04/缓存与Redis/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!