基于 SpringBoot 与 Redis 的缓存预热案例

文章目录

"缓存预热" 是什么?

缓存预热是一种优化策略,在系统启动或者流量高峰来临之前,将一些经常访问的数据提前加载到缓存中。这样做的好处是,当用户实际请求这些数据时,能够直接从缓存中获取,避免了从数据库等慢速数据源中查询数据,从而提高系统的响应速度和吞吐量,减少数据库的压力。

缓存预热通常发生在以下情况下:

  1. 系统投入使用前:

    在系统正式投入使用之前,可以对一些初始化数据进行预热,以避免系统上线初期因为大量数据未被缓存而导致的性能问题。

  2. 数据访问热度周期性变化较高的情况下:

    对于有些数据,其访问热度可能会随着时间变化而变化,可以在预计到达高峰期之前预热这些数据,以确保在高峰期能够直接从缓存中获取,提高系统性能。

实际上,缓存预热是一种以时间换空间的策略,通过预先将需要频繁访问的数据加载到缓存中,来减少后续访问时因为缓存未命中而导致的性能损失。

例如,一个电商网站准备举办大型促销活动,预计将有大量用户访问某一特定类别的商品页面。为了避免在活动期间因为商品数据缓存未命中而导致系统性能下降,可以提前对这一类别的商品信息进行缓存预热。即在活动开始之前,系统可以将这类商品的信息提前加载到缓存中,以确保在活动期间可以直接从缓存中获取数据,提高系统的响应速度。

以下是一个基于 SpringBoot 与 Redis 的缓存预热案例。

项目环境搭建

  • 引入依赖:

    xml 复制代码
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
  • 定义启动类:

    java 复制代码
    package test;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SpringBootApp {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootApp.class, args);
        }
    
    }
  • 定义配置:

    yaml 复制代码
    spring:
      redis:
        # Redis主机IP
        host: localhost
        # Redis主机端口
        port: 6379
        # Redis主机密码
        password:
        # 使用Redis的8号库
        database: 8
        # 使用lettuce客户端
        lettuce:
          # 连接池配置
          pool:
            # 最大连接数
            max-active: 8
            # 最大空闲连接
            max-idle: 8
            # 最小空闲连接
            min-idle: 0
            # 连接等待时间
            max-wait: 100

创建数据访问层

模拟从数据库中获取用户数据。

java 复制代码
package test;

import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

@Repository
public class UserDao {

    /**
     * 模拟从数据库中获取所有用户
     *
     * @return 所有用户
     */
    public List<User> getAllUsers() {
        List<User> users = new ArrayList<>();
        users.add(new User(1L, "Alice"));
        users.add(new User(2L, "Bob"));
        users.add(new User(3L, "Charlie"));
        return users;
    }

}

预热数据到 Redis 中

实现 CommandLineRunner 接口,在 Spring Boot 应用启动时执行缓存预热操作。

java 复制代码
package test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Slf4j
public class CachePreheater implements CommandLineRunner {

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserCacheService userCacheService;

    @Override
    public void run(String... args) {
        // 从数据库获取所有用户数据
        List<User> users = userDao.getAllUsers();
        // 将用户数据缓存到 Redis 中
        userCacheService.cacheUsers(users);
        log.info("Cache preheating completed.");
    }

}

启动 SpringBoot 应用,控制台输出如下结果:

以上结果说明,数据已经成功被预热到缓存(Redis)中。

创建缓存服务类

负责将用户数据缓存到 Redis 中,并从 Redis 中获取用户数据。

java 复制代码
package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class UserCacheService {

    @Resource
    private RedisTemplate<String, User> redisTemplate;

    public void cacheUsers(List<User> users) {
        for (User user : users) {
            redisTemplate.opsForValue().set("user:" + user.getId(), user);
        }
    }

    public User getUserFromCache(Long userId) {
        return redisTemplate.opsForValue().get("user:" + userId);
    }

}

测试缓存预热

创建一个控制器来测试缓存是否预热成功。

java 复制代码
package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserCacheService userCacheService;

    @GetMapping("/users/{userId}")
    public User getUser(@PathVariable Long userId) {
        return userCacheService.getUserFromCache(userId);
    }
    
}

在浏览器中访问 http://localhost:8080/users/1,得到的响应结果:

以上结果说明,成功从缓存中获取到了预热到的数据。

相关推荐
落霞的思绪23 分钟前
Springboot集成SSE实现消息推送+RabbitMQ解决集群环境下SSE通道跨节点事件推送问题
spring boot·rabbitmq·sse
深鱼~1 小时前
【Redis】缓存|缓存的更新策略|内存淘汰策略|缓存预热、缓存穿透、缓存雪崩和缓存击穿
数据库·redis·缓存
nicepainkiller1 小时前
redis高阶2 高性能
数据库·redis·缓存
Algorithm15761 小时前
Redis的ZSet对象底层原理——跳表
数据库·redis·缓存
工业互联网专业1 小时前
基于springboot+vue的健康健身追踪系统
java·vue.js·spring boot·毕业设计·源码·课程设计·健康健身追踪系统
王有品1 小时前
Spring、Spring MVC 与 Spring Boot 的关系与核心用途
spring boot·spring·mvc
brave_zhao2 小时前
使用Spring Boot实现WebSocket广播
spring boot·后端·websocket
听闻风很好吃2 小时前
Redis性能优化终极指南:从原理到实战的深度调优策略
数据库·redis·性能优化
java1234_小锋2 小时前
什么是缓存?在NGINX中如何配置缓存以提升性能?
缓存