缓存击穿问题的三种解决思路

每一次请求查询都会先到Redis缓存中查询是否有数据缓存,如果有就先返回缓存,如果没有就到数据库中查询,把查出来的结果重新写入缓存。但是如果查询的是数据库中都没有的数据,缓存中也无法保留,所以当用户一直请求访问一个不存在的数据的时候,就会一直直接对数据库服务器进行请求,极大影响数据库相关服务的性能。针对这个问题,有三种主流的解决方案:

1、方案一:主动设置空缓存

当接受对于数据库中都没有的查询请求时,主动在redis中写入空数据,同时为了避免请求过多导致空数据过多负载加重,给每一个空数据都设置一个过期时效,所以对于同一个空数据的请求,只有第一次会访问数据库,其余的时候都是停止在缓存层面,有效的缓解了数据库的压力。

2、方案二:互斥锁

方案一设置空数据的机制不够完善,有可能有这么一种极端情形,一秒钟涌入对同一条空数据的上万次查询请求,当数据库接受到第一个请求之后还来不及增加空数据,第二个第三个...请求就又到了数据库,这时候数据库的压力依然很大,容易宕机,由此引出了互斥锁的解决方案。现在很多项目都是分布式的结构,就很难再像Java单机应用一样使用synchronized等把进程锁起来,所以我们采用的方式是锁的概念,借用redis中hash数值类型的setnx方式(如果key不存在,就往redis中存放数据,如果key存在就不存放),当服务器接受到第一个请求的时候获得锁,然后到数据库中查询数据,数据不存在就添加空数据到缓存中;如果数据存在就直接返回;后续未获得锁的请求就休眠一段时间后重新尝试获取锁,没有得到锁就等待,得到锁就重复上续步骤,这里应用到实际的时候还可以添加上最大休眠次数,避免休眠请求数据次数过多,不必要占用内存。

3、方式三:设置逻辑过期时间

像双十一这种特殊时期,就可以往数据库里添加带有逻辑过期时间的数据,即有一个字段是添加的时间加上有效时间,后续查询出这条数据的时候判断是否超过逻辑过期时间,没有过期就返回数据对象;过期了就重复互斥锁的步骤重建缓存。当双十一过后,就可以把插入的数据缓存给清除掉,也避免了插入缓存过多压力大的问题。

posted @ 2022-04-15 21:54  Cra2iTeT  阅读(816)  评论(0编辑  收藏  举报