1.缓存穿透

是指缓存和数据库都没有的数据,而用户不断发起请求,导致数据库压力过大。
解决方案:

  1. 对空值缓存。如果一个查询返回的数据为空(不管数据是否存不存在),仍将这个空结果进行缓存。设置空结果的过期时间很短,最长不超过5分钟。
  2. 设置可访问名单。使用bitmaps类型定义一个可访问名单。名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较。如果访问id不在bitmaps里,进行拦截,不允许访问。
  3. 采用布隆过滤器。
  4. 设置黑名单。

2.缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案:

  1. 预先设置热门数据。在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长。
  2. 实时调整。调整key的过期时间。
  3. 使用锁。

3.缓存雪崩

缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:

  1. 构建多级缓存架构。
  2. 使用锁或者队列。
  3. 设置过期标志更新缓存。
  4. 将缓存失效时间分散开。

4.分布式锁

  1. 跨服务之间上锁,普通的java锁无法处理。将redis中的key当成锁,key不存在表示未上锁,key存在表示上锁。
  2. 使用setnx加上redis本身是单线程保证并发情况下的线程安全,ex设置过期时间防止死锁。
  3. 给key的value设置不同的uuid,每个请求只能释放自己对于uuid的锁。
  4. 释放锁分为两步,一步判断uuid是否是自己,一步是释放锁。这两步需要用lua脚本来保证原子性。