一、缓存存在的意义
在我看来缓存存在的意义只有一个,对于电商等服务化网站来说是 提升用户体验,对于单纯的系统来说是 提升系统运行效率。使用缓存解决的根本问题就是 防止高并发下系统宕机。
再细致一点可以往下分为:
- 减少磁盘IO、缓解DB压力
- 加速DB中对强一致性不高的热点数据访问
- 提高相应速度
- 减少网络访问
·
二、缓存常见问题及解决方案
1. 缓存穿透
恶意使用空键或不存在的键读取缓存,在缓存中没有找到相应键则会去DB中查询,迫使增加DB压力
解决方法: 使用布隆过滤器(一种数据结构,会返回key可能存在或者一定不存在。HashMap也行,但从空间上来说布隆过滤器占用空间大小极低);查不到数据就加入一个短时间的NULL值
·
2. 缓存雪崩
当多数缓存在同一时间段内全部过期,则在这段时间内需要进行大量DB访问,造成DB压力过大宕机
解决方法: 在设置缓存过期时间时一般用固定值+随机值来确定
·
3. 缓存击穿
当某个数据量较大的缓存过期后大量用户同时请求该数据,从而造成数据库请求瞬间增大,造成DB压力过大
解决方法: 加互斥锁,让第一个请求先去数据库中获取数据并将数据置入缓存中,其余请求等待锁释放。(这里推荐①redis分布式锁:简单好用!②jvm锁:适用范围广、性能高,单台服务器一次只允许一个请求到达数据库);热点数据缓存持久化,永不过期,通过定时任务定时更新缓存。
·
4.热点key
某台机器在某一时间段内承受过高的对某一数据的请求量,导致这台机器经受不住压力挂掉
解决方法: 多级缓存,先在本地缓存中查找,再去远程分布式缓存中查找;热点key加随机数,分布在多个redis服务器中,查询时随机查询某台服务器;限流熔断保护,当请求达到某一峰值时返回空白信息,需要重新刷新页面啥的。
·
5.缓存一致性
如何保证每次读取的缓存数据是我更改了数据库后的数据
解决方法: 最简单的方法就是:①更新DB②删除缓存将这两个操作按先后顺序绑在一起进行加锁处理
·
三、缓存更新策略
-
先删缓存,再更新数据库(不推荐)
并发操作下,先删缓存可能会导致来不及更新数据库别的线程已经读取了旧的数据又放在了缓存中。
-
先更新数据库,再删缓存(业界常用)
并发操作下,如果a线程先读数据库旧数据后b线程再接着更新数据库删除缓存a线程此时又开始将旧的数据放入缓存中。但是这种现象极少可能出现。
-
先更新数据库、再更新缓存(不推荐,不仅可能出现脏数据还会无故消耗性能)
-
read/write through(缓存代理)
应用只与缓存交互不与数据库交互,数据库只与缓存交互,由缓存控制数据库数据更新,更新数据时,先更新缓存,缓存再同步更新到数据库。可适用强一致性数据
-
write behind(异步回写策略:Linux页缓存原理、MYSQL InnoDB Cache Pool原理)
更新数据时只更新缓存不更新数据库,缓存会异步批量更新数据库。这样会导致数据丢失,适用于写多读少的场景。