项目中缓存是如何使用的

51 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第32天,点击查看活动详情

只要提到缓存,上来第一个问题,肯定是先问问你项目哪里用了缓存?为啥要用?不用行不行?如果用了以后可能会有什么不良的后果?

为什么要用缓存?

用缓存,主要有两个用途:高性能高并发

高性能:假设有这么一个场景,你有一操作,一个请求过来,mysql非常耗时的查到一个结果,因为数据非常多,使用查询到这个结果花费了100s,那么在下一层继续查询这个结果应该怎么优化?总不能直接重新搞一个?再来100s?

这时候就需要用到缓存了。

image.png

我们可以把第一次查询到的结果放止缓存里面,第二次查找时候,先进入缓存查找,如果缓存没有,就回到数据库查询,如果缓存有,就直接从缓存返回值。这样一来,除了第一次,后续查询都是非常快的。

高并发:在mysql里面,系统支持的数据量并不多,当大量访问进入mysql时候,也意味着数据库快没了。所以我们需要用到缓存。把一些数据放止缓存里面,而不是同时交给数据库,这样可以保证数据库在这段时间内不会没。

使用缓存的问题

1,缓存雪崩,缓存穿透,缓存击穿

缓存雪崩:缓存雪崩是指当缓存失效或过期后引起系统性能急剧下降的情况。

当缓存失效或过期被清除后,系统需要再次访问数据库,再次进行运算重新生成缓存,这个处理步骤耗时比较长,上百毫秒甚至更长时间。而对于一个高并发的系统来说,几百毫秒内可能会接到几百个请求。

由于旧的缓存已经被清除,新的缓存还未生成,并且处理这些请求的线程都不知道另外有一个线程正在生成缓存,所以所有的请求都会去重新生成缓存,都会去访问数据库,对数据库造成巨大的压力和不必要的性能损耗。

这些对数据库的访问压力又会拖慢整个系统,严重的会造成数据库宕机,形成一系列连锁反应,造成整个系统崩溃。

解决办法:在雪崩之前,使用redis缓存,雪崩时候,采用本地缓存和限流操作,雪崩后,迅速采用redis的持久化,进行数据库重启。

缓存穿透:是指查询一个根本不存在的数据,缓存层和持久层都不会命中。可能原因是代码有错,或者被恶意攻击

解决方式是:进行缓存空对象。如果没有命中,就缓存空对象。进行过滤,在过滤时候,把不存在的key滤出去

缓存击穿:缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞

解决方法是:把这个热点key设置永不过期

2.redis之间的并发竞争

redis并发竞争是多个客户端并发写一个key,本来应该是先到的请求先写key,但可能由于网络环境差异,先发起的请求后到了,导致value最终被后发起的请求修改,最终数据错乱了。或者是多个客户端同时获取一个key,修改之后再写回去,只要顺序错了,数据就错了。

mysql需要一个时间戳。每次要写之前,先判断一下当前这个 value 的时间戳是否比缓存里的 value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。