缓存 【穿透、击穿、雪崩】
什么是缓存穿透?
概念:查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库。
原因:发生这个情况是因为有人恶意请求,知道了请求路径,一直请求不存在的数据,而数据库并发量并不高,因此请求量到了一定程度就会导致数据库宕机。
解决办法
1.缓存空数据,直接将数据库null值传给redis,好处是实现方便,坏处是内存占用大,数据可能不一致,可能数据库本来null的值传入了值,但是redis那边还是null。
2.布隆过滤器。好处是内存占用较少,没有多余key,因为是基于bitmap实现的,缺点是实现复杂,有误判,是因为经过三次hash运算后对应角标的位置可能都是1,但是实际上redis里面并没有这个值,一般项目误判率在百分之五以内都是可以接受的。
什么是缓存击穿?
概念:给某个key设置了过期时间。但是恰好过期的时间点对这个key有大量的并发请求过来了,redis查不到就会去查数据库,那就会瞬间把数据库压垮。
解决办法
1.互斥锁(适用于与 钱 相关场景,需要保证数据强一致性)
只会有一个线程获得锁后进行缓存重建,其他线程就得等待,直到数据库数据写入redis,性能相对比较低,数据保持强一致性。
2.逻辑过期或者设置为不过期(用于互联网行业,高可用性,用户体验好)
第一个线程获得互斥锁,开启一个新的线程进行数据重构,然后直接返回过期数据,在新线程写入缓存重置过期时间后才会释放锁,在此期间其他线程来查询缓存发现逻辑时间过期了,想获取互斥锁会失败,直接返回过期数据,因此性能好,但是不能保证数据绝对一致。
什么是缓存雪崩?
缓存雪崩是指大量的key在同一时期过期或者redis宕机导致大量请求到达数据库,带来巨大压力
解决办法:
1.给不同的key的TTL添加随机值,防止key在同一时间失效
2.利用redis集群提高服务的可用性,比如redis集群,哨兵模式
3.给缓存业务添加降级限流策略,nginx或者spring cloud gateway,作为系统的保底策略,适用于【穿透、击穿、雪崩】
4.给业务添加多级缓存,比如Guava或Caffeine作为一级缓存,redis作为二级缓存