🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
一.缓存雪崩,缓存穿透,缓存击穿 1.缓存穿透: key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库 解决方案(最粗暴的): 如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟 缺点:如果key数量巨大且分散无任何规律,就会浪费大量缓存空间,并且不能抗住瞬时流量冲击 2.缓存击穿(#热点key): key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮 解决方案: 业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。 3.缓存雪崩: 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力 解决方案: 使用锁或队列、设置过期标志更新缓存、为key设置不同的缓存失效时间,还有一种被称为“二级缓存”的解决方法; 方案:设置过期标志更新缓存 做缓存标记,记录缓存数据是否过期;标记缓存时间30分钟,数据缓存设置为60分钟。这样,当缓存标记key过期后,实际缓存还能把旧数据返回给调用端,直到另外的线程在后台更新完成后,才会返回新缓存 方案: 双层缓存策略 C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期 4.总结 ![](https://img.kancloud.cn/57/48/5748f30902cba0319b60750edf42de01_700x517.png) 二.缓存与数据库双写不一致 (1)只读缓存( **`Cache Aside` ****模式)** ![](https://img.kancloud.cn/ff/f1/fff186f08c0c8a1a1aed15401580be39_627x454.png) 总结出, 当不存在并发的情况使用重试机制(消息队列使用),当存在高并发的情况,使用延迟双删除(在第一次删除后,睡眠一定时间后,再进行删除) (2)读写缓存(Read/Write-Throug、Write Behind模式 ) ![](https://img.kancloud.cn/14/d9/14d964a3e6554bc0a4b9851d0486ff78_605x730.png) 总结出,当不存在并发的情况使用重试机制(消息队列使用),当存在高并发的情况,使用分布锁