记一次缓存击穿的解决
作者:互联网
参考:
Redis 缓存雪崩、缓存穿透、缓存击穿、缓存预热
《我们一起进大厂》系列-缓存雪崩、击穿、穿透
一行代码解决缓存击穿问题
然、聪
先看下缓存击穿的概念:
缓存击穿指的是某个热点缓存,在某一时刻恰好失效了,然后此时刚好有大量的并发请求,此时这些请求将会给数据库造成巨大的压力,这种情况就叫做缓存击穿。
说下我遇到的问题:
项目中需要请求其他远程接口的数据,这些数据会在本地接口处理一些请求的时候被使用。
首先避免频繁请求远程接口拿数据,先做个缓存:本地接口处理请求时优先查缓存,没有再请求接口获取数据并更新。
以上逻辑很简单常用,但考虑到我使用了缓存数据的本地接口可能会有很大的并发,如果缓存没有或者失效的情况,就会有很多并发线程同时去请求远程接口,给远程接口造成很大的压力,同时影响了本地接口的响应速度。
下面说下解决思路:
1、加锁排队。
优先查缓存,查不到缓存,就使用redis锁更新缓存。
redis锁:向redis写入更新缓存开始的标记,同时请求远程接口并更新缓存,更新完毕清除redis的标记。其他线程如果查到redis标记存在,就while True阻塞等待直到查出缓存。
该方法的缺点是阻塞了本地接口的并发处理,可能带来潜在问题。
2、逻辑过期时间
缓存设置永不过期,在写入缓存数据时加上生成时间和有效时间,读取缓存时判断时间是否过期,如果过期,就加上redis标记去更新缓存(保证同时只有一个线程更新缓存),其他线程检查到redis更新缓存标记已存在,就直接取走过期的缓存。
3、二级缓存
缓存两份数据,一份设置过期时间,另一份设置永不过期作为二级缓存。优先查缓存,查不到缓存,就查二级缓存,并加上redis标记去更新缓存,其他线程检查到redis更新缓存标记已存在,就直接取走二级缓存。
还有2个要注意的点:
1、在上述逻辑过期、二级缓存方法中, 更新缓存这个动作可以写个异步任务去完成。
2、在上述逻辑过期、二级缓存方法中,为了解决第一次查缓存就没有数据导致高并发穿过缓存的情况,需要在上线前就准备好缓存数据(比如在django的migrate中或者celery的@worker_ready.connect信号中更新缓存)。
3、其实还有一种办法也可以解决项目中的问题,就是设置一个定时任务去缓存全量数据,但是我觉得太臃肿,太依赖celery
标签:缓存,过期,击穿,redis,接口,二级缓存,更新,解决 来源: https://www.cnblogs.com/libaiyun/p/16477367.html