【Redis】缓存穿透和缓存雪崩

缓存穿透 (查不到)

数据库中没有, 缓存中自然没有, 所以就会频繁的去数据库中查.

布隆过滤器

布隆过滤器式一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力.

pravate static BloomFilter<Integer> bloomFilter = BloomFilter.create(FUnnels.integerFunnel(),size,fpp);
//本质是一个集合 内置是bitmaps 利用的是 位图  0 1  m

利用若干 个HASH 函数 ,先把所有数据添加进去,新的来了 查看 只要有一个为0 那么就是一定不存在,若都为一 ,可能存在,这个时候先去redis 找,找不到再去数据库。

缺点:维护比较麻烦,而且不能删除 所以要定期维护

缓存空对象

当存储层不命中后,将返回的空对象存储起来,同时设置一个过期时间,之后在访问这个数据就会从缓存中获取

缓存击穿(量太大,缓存过期)

一个数据刚刚好失效,或者缓存中没有这个数据 这个时候并发访问.

也就是缓存击穿是量太大了,一个key非常热点,大并发集中对这一个点进行访问,这个key失效的瞬间,持续的大并发就穿破缓存,直接请求数据库

设置热点数据永不过期

但是永不过期 会有别的问题

加互斥锁

分布式锁: 使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可.
这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大.

  1. 为什么需要分布式锁
    如果原本我们的系统分布在一台机器上的时候,JVM提供的锁就能解决并发问题。但是如果我们是使用多台机器,要同时去Redis里面去拿同一个Key 这个时候,就会发生并发问题,因为这个时候JVM的锁事无法解决这个问题。
  2. 基于Resid的分布式锁
  • 最简单的方法是使用setnx 命令,Key 是锁的唯一标识(加锁

    • setnx key value :是去redis尝试set 如果里面已经有key 那么就设置失败返回0

    ps:这里其实就是利用的redis的原子性 实现了CAS的效果。

  • 有加锁就得有解锁。当得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入。释放锁的最简单方式是执行 del 指令(解锁

    • del key:删去Key 达到解锁的效果
  1. 锁超时
    因为如果宕机 不给锁设置超时,那么就会死锁 ,所以在 setnx的时候需要设置超时时间。expire key times
  2. 问题!
  • 第一点: 在加锁和锁超时的时候 不是原子操作
    • 解决方案:可以利用lua ,set 可以添加可选参数
  • del 误删:如果某个业务逻辑的时间超过了超时时间,这个时候如果key 已经被删除了就会有第二个逻辑进来操作 从而没有达到锁的效果。
    • 解决方案:使用守护线程 一直去给我们的key 加上超时时间,这样会让锁不被释放。
      • 守护线程:开辟一个线程 如果主线程挂了或者结束 那么守护线程也会结束。

缓存雪崩

在某一个时间段,缓存集中过期失效,或者Redis宕机.

redis高可用

既然redis有可能挂,就多增设几台redis
即高可用高效集群

限流降级

在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量.

数据预热

在正式部署前,先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中. 在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章