缓存穿透、缓存雪崩、缓存击穿区别
1.缓存穿透
缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。
-
如果用户请求返回null,这时就会重新发起请求,如果有不怀好意的人发起大量数据库不存在的请求,那么就有可能将数据库弄垮,那么怎么解决这个问题呢?
-
缓存空对象:请求的数据如果不存在,那么我就把请求返回的null,也存到redis里面。这时请求就有数据了,就是null。
- 优点:实现简单,维护方便
- 缺点:
- 额外的内存消耗(就是各种不存在的数据我都缓存了,我们可以专门给null的数据加个过期时间)
- 可能造成短期的不一致(就是查询的数据不存在,我就缓存了一个null,但是这时数据库刚好插入了这个数据,就造成了数据短期不一致,也可以通过设置过期时间缓解。也可以在插入数据库时主动更新缓存)
-
布隆过滤:就是客户端和redis之间加了一层布隆过滤器,如果数据不存在,直接拒绝,存在才放行。那布隆过滤器怎么知道数据是否存在呢?
- 布隆过滤器简单可以理解为byte[]里面根据0/1判断是否存在该数据
- 优点:内存占用较少,没有多余key
- 缺点:
- 实现复杂
- 存在误判可能
-
增强id的复杂度,避免被猜测id规律,做好数据的基础格式校验:
- 我们可以通过在请求的时候直接对id格式进行校验,因为我们把id格式设置不太容易被猜测,一定程度上可以解决缓存穿透问题
-
加强用户权限校验:比如访问网站要登录等等
-
做好热点参数的限流:比如对null值进行限流等
-
2.缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
- 解决方案:
- 给不同的Key的TTL添加随机值
- 利用Redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
3.缓存击穿
缓存击穿问题也叫热点Key问题,就是一个被
高井发访问
并且缓存重建业务
较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。
-
解决方案:
-
互斥锁:
- 如果key过期,查询缓存未命中,就去获取锁,只有获取锁的线程才能查询数据库重建缓存数据。此时后面的线程没有获取锁,就不能查询数据库,线程休眠一会,重新查询缓存,不断重复
- 优点:没有额外的内存消耗、保证一致性、实现简单
- 缺点:所有线程都在等一个线程重建缓存数据,如果这个线程执行的很久,性能就会比较差,可能有死锁的风险
-
逻辑过期:
-
我们给value添加一个逻辑过期时间,可以理解就添加一个字段(如{key1:value1,expire:15214123}),这时我们是可以查到数据的,此时如果判断这个key过期了,我们就获取一个互斥锁,准备去重建缓存数据。但是和上面不同的是,这时这个线程就会新开启一个线程去重建数据,那这个线程干啥呢?那就是返回我们查到的逻辑过期的数据。其他获取互斥锁失败的就不会重试了,同样的会直接返回逻辑过期的数据。
-
优点:线程无需等待、性能较好
-
缺点:不保证一致性、有额外内存消耗、实现复杂
-
-