天天看点

Spring Boot 进阶-Spring Boot整合Redis实战缓存穿透

作者:架构师面试宝典
Spring Boot 进阶-Spring Boot整合Redis实战缓存穿透

缓存的引入极大地提升了系统的整体的查询效率和执行效率,但是也带来了一些新的问题,其中不乏有很多经典的问题包括缓存穿透、缓存雪崩、缓存击穿等等。对于这些问题,现在业界都有自己对应的解决方案,下面我们就来通过一个缓存穿透的例子来通过代码实战的方式来看看如何去解决缓存穿透问题。

在上篇文章中,我们介绍了在Spring Boot中如何整合Redis,这里我们就通过上篇文章中的例子来实现缓存穿透案例。首先我们先来看看什么是缓存穿透

缓存穿透

使用缓存的目的就是减少用户流量对于数据库的压力。如下图所示,当用户请求需要查询数据的时候,后端应用会先从缓存中进行查找,如果查询到数据那么就会直接返回数据给用户,这个时候整个的查询流程就结束了。但是如果在缓存中没有查询到数据,则说明缓存中没有缓存相关数据,这个时候就说明有其他的操作可能更新了数据,但是缓存中没有,这个时候就需要到数据库中进行查询,如果获取到了数据,那么接下来完成两个操作,第一个操作就是将获取到的数据返回给用户,第二个操作就是按照规则将数据放入到缓存中。

Spring Boot 进阶-Spring Boot整合Redis实战缓存穿透

那么在这个过程中,就会有这样一个问题,如果在整个的查询过程中,无论是缓存中,还是在数据库中都没有查询到数据的时候,这个时候数据既不在数据库中,也不会在缓存中,那么如果这样的请求大批量的进行请求的时候,就会导致数据库中有大量的查询操作进入,这个时候就会导致数据库宕机,拒绝服务。最终导致数据库服务器的损坏。而这就是所谓的缓存穿透所带来的问题。

那么我们如何去解决这个问题呢?

缓存穿透解决方案

业界解决缓存穿透都有自己普遍的成熟解决方案。其中比较成熟的就是对如果在数据库中没有查询到数据的时候的操作进行优化处理,最终达到解决缓存穿透问题解决的目的。

如果没有查询到数据,则将NULL返回给前端客户端的同时,将NULL也写入到缓存中,并且对对应的Key值设置一个指定过期时间,这样如果是存在网络延迟的情况导致数据没有及时同步的时候,当Key过期了,也会从数据库中更新新的数据存储到缓存中。这种方案在一定程度上可以减轻数据库的查询压力。

代码实战

创建一个模拟的用户服务调用代码如下

@RestController
public class CacheController {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private UserService userService;

    @GetMapping("/getInfo")
    public Object getInfo(@RequestParam("id") Integer id){

        User user = redisCache.getCacheObject(String.valueOf(id));

        if (user!=null){
            return user;
        }else {
            User user1 = userService.getUser(id);
            if (user1!=null){
                redisCache.setCacheObject(String.valueOf(id),user1);
            }else {
                redisCache.setCacheObject(String.valueOf(id),user1,10, TimeUnit.SECONDS);
            }
            return user1;
        }
    }
}
           

编写好之后,我们启动项目在浏览器中访问指定用户ID就会看到数据正常返回,并且进行缓存存储。否则则返回NULL,并且在缓存中设置一个过期时间。当这个过期时间到了之后,缓存中的Key就会清除。如果数据库存在了对应的id,这个时候就会进行正常的查询逻辑将数据存储到缓存中。当然在这个过程中还会涉及到其他的问题。例如缓存更新、缓存失效等问题。例如上面如果我们将所有的失效时间都设置成10秒,那么在十秒之后,缓存中会有大量的KEY失效,就会带来缓存雪崩等问题。所以这里只是通过一个小例子来展示如何解决缓存穿透问题。在整个缓存机制中还有各种各样的问题等着我们去解决。

Spring Boot 进阶-Spring Boot整合Redis实战缓存穿透

总结

在实际开发过程中我们要根据业务的实际性质来决定使用什么样的缓存策略,对于一些长期不变的内容我们可以是采用手动清理缓存的操作,而对于一些需要实时更新的内容,我们就需要采用到其他的缓存策略来进行存储,这样才能更好的保证我们的用户体验。

继续阅读