1. 缓存穿透
缓存穿透是指查询的key在缓存中是不存在的,那么就会直接打在数据库上,造成数据库压力增大。
eg: 如果请求带着id过来了,像查询id=-1的数据,
于是缓存里自然没有该数据,因为数据库本来也就没有该数据。
那这个就有趣了,如果不断大量恶意请求,那就是直接绕过缓存,
一直在查数据库,给数据库造成极大的压力,这就是缓存穿透。
解决方案:
a、在逻辑代码处做一层请求校验
id的请求范围校验。如果请求的参数不符合规矩那就直接拒绝请求了,连缓存都拒绝请求了更别说请求到数据库了;
b、尽量坏数据也做缓存
比如恶意请求的参数缓存和数据库库都获取不到数据一次就直接缓存为坏数据一段时间
(比如有一个缓存池key都为bad_id系列,id请求过来后先查询key=bad_id系列是否有数据,没有的话再请求key=id的缓存数据),
这样就可以缓解恶意请求带来的压力;
c、那如果不是恶意请求,比如正常id=1的请求,此时刚好缓存没数据,数据库也查不到数据时,也是建议缓存处理
但这个缓存时间要根据实际业务情况设置,不宜过长,比如30秒,否则会影响正常情况的获取
d、布隆过滤器
可以使用布隆过滤器解决缓存穿透的问题,把已存在数据的key存在布隆过滤器中。
当有新的请求时,先到布隆过滤器中查询是否存在,如果不存在该条数据直接返回;
如果存在该条数据再查询缓存查询数据库。
当布隆过滤器说,某种东西存在时,这种东西可能不存在;当布隆过滤器说,某种东西不存在时,那么这种东西一定不存在。
2. 缓存击穿
缓存击穿就是当请求参数过来,缓存中的数据瞬间过期,此时并发量又大,全部请求直接同时转为去请求数据库,瞬间给数据库带来巨大压力。
解决方案:
a、设置热点数据永远不过期(简单粗暴)
b、加互斥锁
就是同一时间只能有一个请求去查询数据库更新缓存。
然后其他请求再从缓存中取数据。
代码实现方式:
对缓存过期后去请求数据库的操作加互斥锁,其他获取不到锁的请求直接等待(sleep)数秒后再去重新请求获取数据的方法,自然就能从缓存取数据了。
c、将同一热点数据均匀分布在不同的缓存节点中
比如将key哈希分散存储,如id_hash(openid),单独设置过期时间),这样即可分散热key对redis的压力也可避免同一时间过期后大量请求一起同时涌向数据库查询数据。
缓存穿透和击穿的区别
缓存穿透 | 缓存击穿 |
缓存无数据数据库也无数据 | 缓存无数据数据库有数据 |
攻击行为导致 | 缓存处理不当导致 |
3. 缓存雪崩
缓存雪崩是指缓存中数据大批量同时到过期时间。
(eg: redis服务突然挂了后重启,而查询数据量巨大,引起数据库压力过大甚至down机。)
和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案:
a、设置热点数据永远不过期;
b、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生,就是将缓存过期时间设置错开;
c、将热点数据均匀分布在不同的缓存节点中,这样即可防止热点压力,又可以防止缓存同一时间过期,导致雪崩。