注:该文章基于黑马程序员中《黑马点评》软件的学习
视频链接
涉及视频
p40
p42
p43
缓存穿透
是指客户端请求的数据在缓存和数据库中都不存在,这样缓存永远不会生效,这些请求全部被打到数据库。
产生的原因:
1.请求的id缓存不存在
2.用户恶意请求系统不可能配置的id
常见的俩种解决方案:
1.缓存空对象
将从数据库中没有查询到的结果返回一个空给缓存,并且给缓存设置一个有效时长
优点: 实现简单,维护方便
缺点: 1.额外的内存消耗
2.可能照成短期的不一致(当返回null时,数据库添加了id的信息,存在一个小于等于TTL时长的缓存和内存数据不一致的情况)
2.布隆过滤器
布隆过滤器通过hash算法将数据库的数据计算出hash值,将hash值转换成二进制数保存在布隆过滤器里,因为是二进制数,所以布隆过滤器不会产生很大的缓存消耗
优点: 内存占用较少,没有多余的key
缺点: 1.实现复杂(目前redis中可以直接调用)
2.存在误判的可能(布隆过滤器判定不存在,数据库中肯定不存在,布隆过滤器判断存在,可能数据库中不存在)
其他方法:
1.增强id的复杂度,避免被猜测id规律
2.做好数据的基础格式校验
缓存雪崩
同一时间段大量的缓存key同时失效或者redis服务宕机,导致大量的请求到达数据库,带来数据库巨大的压力
解决方案:
1.给不同的key配置随机的TTL值,让他们不会出现同时失效的情况
2.利用redis集群提高服务的高可用性
3.给缓存业务添加降级限流策略
4.给业务添加多级缓存
缓存击穿(热点问题)
一个高并发访问并且缓存重建业务比较复杂的Key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击
常见的俩种解决方案:
1.互斥锁
单第一个线程缓存未命中的时候,对缓存上互斥锁,然后开始查询数据库,与此同时来查询缓存的其他线程,发型缓存未命中,也要开始开启互斥锁,但是被第一个互斥锁挡住,无法开启,于是其他线程循环查询查询缓存和尝试开始互斥锁直到第一个线程在数据库中查询到数据并且写入缓存,其他缓存才可以命中缓存(目的在于只有一个线程查询数据库,其他线程等待)
逻辑过期
我们在存储这个信息到缓存时不设置TTL,设置一个值(当前的时间+持续的时间)来了解他的逻辑过期时间。
当我们出现第一个线程查询缓存发现逻辑时间已经过期的时候,开启互斥锁
第一个线程开启另一个线程来完成查询数据库和写入缓存等工作,最后释放互斥锁
与此同时第一个线程返回过期的缓存数据。
其他刚来的线程发现逻辑时间过期,获取互斥锁失败,也返回过期的缓存数据
直到第一个缓存开启的另一个缓存释放锁后到来的线程可以查询到最新的缓存数据