当前位置: 首页 > news >正文

缓存预热有哪些方案?

一道经典面试题:缓存预热有哪些方案?

在系统业务高峰期到来之前,我们提前将一些热点数据加载到缓存中,进而提高系统的响应速度,这就是所谓的缓存预热。

那么怎么实现缓存预热呢?

一般来说,我们主要有三种思路:

  • 系统启动时加载缓存。
  • 定时任务加载缓存。
  • 使用缓存加载器。

每种里边往往又对应了不同的具体方案,我们逐一来看。

一 系统启动时加载缓存

这个就是利用系统启动时候的一些钩子函数,或者如事件监听机制或者是框架专为系统启动预留的方法,在这些方法中去加载缓存。

这里松哥给四个常见的思路。

1.1 启动监听事件

使用 ApplicationListener 监听 Spring Boot 启动完成的事件,如 ContextRefreshedEventApplicationReadyEvent,在事件触发后加载数据到缓存。

举个栗子:

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@Component
public class CacheWarmer implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 假设有一个缓存管理器cacheManagercacheManager.put("key1", "松哥");cacheManager.put("key2", "江南一点雨");// ... 加载更多数据到缓存}
}

1.2 @PostConstruct 注解

使用 @PostConstruct 注解在 Spring Bean 初始化后立即执行缓存预热逻辑。

举个栗子:

import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;@Component
public class CachePreloader {private final CacheManager cacheManager;public CachePreloader(CacheManager cacheManager) {this.cacheManager = cacheManager;}@PostConstructpublic void preloadCache() {cacheManager.put("key1", "江南一点雨");cacheManager.put("key2", "松哥");// ... 加载更多数据到缓存}
}

1.3 CommandLineRunner 或 ApplicationRunner

实现 CommandLineRunnerApplicationRunner 接口,在 Spring Boot 启动后执行缓存预热。

CommandLineRunner 案例:

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class MyCommandLineRunner implements CommandLineRunner {private final CacheManager cacheManager;public MyCommandLineRunner(CacheManager cacheManager) {this.cacheManager = cacheManager;}@Overridepublic void run(String... args) throws Exception {cacheManager.put("key1", "江南一点雨");cacheManager.put("key2", "松哥");// ... 加载更多数据到缓存}
}

ApplicationRunner 案例:

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Component
public class MyApplicationRunner implements ApplicationRunner {private final CacheManager cacheManager;public MyApplicationRunner(CacheManager cacheManager) {this.cacheManager = cacheManager;}@Overridepublic void run(ApplicationArguments args) throws Exception {cacheManager.put("key1", "江南一点雨");cacheManager.put("key2", "松哥");// ... 加载更多数据到缓存}
}

1.4 InitializingBean接口

实现 InitializingBean 接口,并在 afterPropertiesSet 方法中执行缓存预热。

案例:

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;@Component
public class CachePreloader implements InitializingBean {private final CacheManager cacheManager;public CachePreloader(CacheManager cacheManager) {this.cacheManager = cacheManager;}@Overridepublic void afterPropertiesSet() throws Exception {cacheManager.put("key1", "松哥");cacheManager.put("key2", "江南一点雨");// ... 加载更多数据到缓存}
}

在这些案例中,CacheManager是一个假设的缓存管理器,你需要根据实际使用的缓存技术(如 Redis、EhCache 等)来实现或注入相应的缓存管理器。这些代码片段展示了如何在 Spring Boot 应用启动后,通过不同的方式加载数据到缓存中,以减少应用启动后的首次加载延迟。

在系统启动时加载缓存往往有一个问题,就是这些缓存加载之后,不会主动更新。如果我们需要对缓存进行定期更新,那么就可以考虑使用定时任务去加载缓存。

二 定时任务加载缓存

一般来说,如果我们面对以下需求时,就可以考虑使用定时任务加载缓存。

  1. 数据依赖性:当缓存的数据依赖于外部系统或数据库的定期更新,且这些更新不是实时触发的,而是按照一定的时间间隔发生时,可以通过定时任务来预热缓存。
  2. 数据量大:如果预热的数据量非常大,一次性加载可能会对系统性能产生影响,可以通过定时任务分批次逐步加载数据到缓存中。
  3. 依赖多个数据源:当缓存的数据需要从多个数据源聚合时,可以通过定时任务来协调这些数据源的更新,确保缓存的数据一致性和准确性。
  4. 业务逻辑复杂:如果缓存预热的业务逻辑比较复杂,涉及到多步骤处理或者需要等待某些异步操作完成,定时任务可以在特定时间点触发这些复杂的业务逻辑。
  5. 资源分配:在资源受限的环境中,为了避免在应用启动时占用过多资源,可以通过定时任务在系统资源较为空闲的时候进行缓存预热。

举个栗子:假设有一个电商网站,商品信息每天凌晨由供应商更新,并且更新操作不是实时的。在这种情况下,可以设置一个定时任务,在每天凌晨更新完成后,将最新的商品信息加载到缓存中,以便用户在白天访问时能够快速获取到最新的商品数据。

在 Spring 框架中,我们可以使用 @Scheduled 注解来实现定时任务:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class CacheWarmUpTask {private final CacheManager cacheManager;public CacheWarmUpTask(CacheManager cacheManager) {this.cacheManager = cacheManager;}@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行public void warmUpCache() {// 执行缓存预热逻辑cacheManager.put("key1", "江南一点雨");cacheManager.put("key2", "松哥");// ... 加载更多数据到缓存}
}

@Scheduled 注解用于指定定时任务的执行计划,cron 表达式定义了任务的执行时间。这样,每天凌晨 1 点,定时任务就会执行,将数据加载到缓存中。

三 使用缓存加载器

缓存加载器(Cache Loader)用于在缓存中自动加载数据。

当缓存中缺少请求的数据时,缓存加载器会被触发,以便从原始数据源(如数据库、文件系统或其他服务)中加载数据并将其放入缓存中。

缓存加载器的主要目的是减少直接从原始数据源加载数据的延迟,提高数据访问的速度。

缓存加载器通常与缓存库或框架一起使用,如 Guava Cache、EhCache、Caffeine 等。在 Spring Cache abstract 中,也可以通过自定义的缓存管理器来实现缓存加载器的功能。

3.1 使用缓存加载器步骤

  1. 定义缓存加载器逻辑:首先,我们需要定义一个加载数据的逻辑,这个逻辑会在缓存中缺失数据时被调用。
  2. 配置缓存:在缓存配置中指定缓存加载器。
  3. 预加载数据:在应用启动时或在特定时间点,通过调用缓存的获取方法来触发缓存加载器,从而预先加载数据到缓存中。
  4. 定时任务:如果需要定期更新缓存,可以结合定时任务(如 Spring 的 @Scheduled 注解)来定期触发缓存加载器。

3.2 举个栗子

Caffeine 是一个高性能的 Java 缓存库,它提供了丰富的缓存策略和灵活的配置选项。Caffeine 并没有直接的缓存预热 API,但是可以通过在应用启动时预先加载数据到缓存中来实现缓存预热的效果。

下面是使用 Caffeine 进行缓存预热的步骤:

  1. 定义缓存:首先,你需要定义一个 Caffeine 缓存实例,并配置相应的缓存策略。
  2. 预加载数据:在应用启动时,通过显式调用缓存的 get 方法或使用 getAll 方法来加载数据到缓存中。
  3. 监听器:如果需要在缓存加载时执行额外的操作,可以配置 CacheLoader 的监听器。
  4. 异步加载:如果数据加载是异步的,可以使用 AsyncLoadingCache 接口来处理异步加载的情况。

代码案例

定义缓存

import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;import java.util.concurrent.TimeUnit;public class CacheInitializer {public static LoadingCache<String, String> createCache() {CacheLoader<String, String> loader = new CacheLoader<String, String>() {@Overridepublic String load(String key) {// 模拟从数据库或其他数据源加载数据return "Value for " + key;}};return Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后过期时间.maximumSize(1000) // 设置最大缓存项数.build(loader);}
}

预加载数据

import com.github.benmanes.caffeine.cache.LoadingCache;import java.util.Arrays;
import java.util.concurrent.ExecutionException;public class CacheWarmUp {private final LoadingCache<String, String> cache;public CacheWarmUp(LoadingCache<String, String> cache) {this.cache = cache;}public void warmUp() throws ExecutionException {// 预加载数据到缓存Arrays.asList("key1", "key2", "key3").forEach(key -> {try {cache.get(key); // 这将触发加载器加载数据} catch (ExecutionException e) {e.printStackTrace();}});}
}

在 Spring Boot 应用中使用

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class CacheWarmUpRunner implements CommandLineRunner {private final LoadingCache<String, String> cache;public CacheWarmUpRunner(LoadingCache<String, String> cache) {this.cache = cache;}@Overridepublic void run(String... args) {try {new CacheWarmUp(cache).warmUp();} catch (Exception e) {e.printStackTrace();}}
}

在这个示例中,CacheInitializer 类定义了一个 Caffeine 缓存实例,CacheWarmUp 类包含了预加载数据到缓存的逻辑。CacheWarmUpRunner 是一个 Spring Boot 的 CommandLineRunner,它在应用启动时调用 CacheWarmUp 类来预加载数据。

通过这种方式,你可以在应用启动时预先加载数据到 Caffeine 缓存中,从而实现缓存预热。这对于提高应用的响应速度和减少首次加载延迟非常有帮助。

上面的案例本质上还是利用了 CommandLineRunner,不过,LoadingCache 在配置的时候,其实也可以设置一个自动刷新的时间,这样就不需要 CommandLineRunner 了,系统会自动执行。

好啦,缓存预热的三种思路,小伙伴们平时都是怎么做的?欢迎留言讨论。

相关文章:

缓存预热有哪些方案?

一道经典面试题&#xff1a;缓存预热有哪些方案&#xff1f; 在系统业务高峰期到来之前&#xff0c;我们提前将一些热点数据加载到缓存中&#xff0c;进而提高系统的响应速度&#xff0c;这就是所谓的缓存预热。 那么怎么实现缓存预热呢&#xff1f; 一般来说&#xff0c;我…...

「iOS学习」——Masonry学习

iOS学习 前言Masonry的属性Masonry的使用基础APIAuto Boxing修饰语倍数中心点设置边距优先级使用 总结 前言 暑假我们学习了使用CocoaPods引入第三方库&#xff0c;实现使用SVG图片。而Masonry作为一个轻量级的布局架构&#xff0c;在使用中可以节省很多时间。故进行简单学习。…...

828华为云征文|华为云Flexus云服务器X实例之openEuler系统下部署GitLab服务器

828华为云征文&#xff5c;华为云Flexus云服务器X实例之openEuler系统下部署Gitlab服务器 前言一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、GitLab介绍2.1 GitLab简介2.2 GitLab主要特点 三、本次…...

51单片机的无线病床呼叫系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温湿度传感器模块矩阵按键时钟模块等模块构成。适用于病床呼叫系统、16床位呼叫等相似项目。 可实现基本功能: 1、LCD1602实时显示北京时间、温湿度信息、呼叫床位等信息&#xff1b; 2、DHT11采集病房温湿度信息&…...

计算机毕业设计 | SpringBoot+vue 游戏商城 steam网站管理系统(附源码)

1&#xff0c;项目背景 国家大力推进信息化建设的大背景下&#xff0c;城市网络基础设施和信息化应用水平得到了极大的提高和提高。特别是在经济发达的沿海地区&#xff0c;商业和服务业也比较发达&#xff0c;公众接受新事物的能力和消费水平也比较高。开展商贸流通产业的信息…...

【CH395的简单示例代码】

提供一个基于CH395的简单示例代码&#xff0c;这里将展示如何初始化CH395&#xff0c;并发送一个简单的HTTP请求。请注意&#xff0c;实际使用时还需要根据具体的硬件平台和开发环境调整代码。 假设我们使用的是一个具有SPI接口的微控制器&#xff0c;并且已经将CH395连接到该…...

AI模型:追求全能还是专精?

目录 引言 一、全能型AI模型的诱惑 1.1 通用智能的愿景 1.2 资源整合的优势 1.3 应对未知挑战的能力 1.4 挑战与不足 二、专精型AI模型的魅力 2.1 深度与精度的提升 2.2 成本控制与效率优化 2.3 易于监管与解释性增强 2.4 挑战与不足 三、全能型与专精型AI的全面评…...

ffmpeg音视频开发从入门到精通——ffmpeg 视频数据抽取

文章目录 FFmpeg视频处理工具使用总结环境配置主函数与参数处理打开输入文件获取流信息分配输出文件上下文猜测输出文件格式创建视频流并设置参数打开输出文件并写入头信息读取、转换并写入帧数据写入尾信息并释放资源运行程序注意事项源代码 FFmpeg视频处理工具使用总结 环境…...

Node.js之文件夹的操作

1.创建文件夹操作 // 导入fs模块 const fs require(fs)//创建文件夹操操作 fs.mkdir(./Page, err > {if (err) {console.log(操作失败)return}console.log(操作成功) }) 2.递归创建文件夹 //递归创建文件夹 fs.mkdir(./a/b/c, {recursive: true}, err > {if (err) {co…...

线程的四种操作

所属专栏&#xff1a;Java学习 1. 线程的开启 start和run的区别&#xff1a; run&#xff1a;描述了线程要执行的任务&#xff0c;也可以称为线程的入口 start&#xff1a;调用系统函数&#xff0c;真正的在系统内核中创建线程&#xff08;创建PCB&#xff0c;加入到链…...

自我指导:提升语言模型自我生成指令的能力

人工智能咨询培训老师叶梓 转载标明出处 传统的语言模型&#xff0c;尤其是经过指令微调的大型模型&#xff0c;虽然在零样本&#xff08;zero-shot&#xff09;任务泛化上表现出色&#xff0c;但它们高度依赖于人类编写的指令数据。这些数据往往数量有限、多样性不足&#xf…...

使用Node.js实现单文件上传功能—含代码解释

1、概念 文件上传的具体内容 在前端让用户发送(上传)图片&#xff0c;图片由后端(服务器)接收&#xff0c;并转存到到服务端设备上的操作node.js的文件上传功能主要是使用&#xff1a;multer 插件实现的 搭建一个图片上传的接口 先让接口开通&#xff0c;再去做插件下载/配置等…...

【机器人工具箱Robotics Toolbox开发笔记(一)】Matlab机器人工具箱简介

MATLAB是一款被广泛应用于科学计算和工程领域的专业软件。它的全称为Matrix Laboratory&#xff08;矩阵实验室&#xff09;&#xff0c;因为其最基本的数据类型就是矢量与矩阵&#xff0c;所以在处理数学和科学问题时非常方便&#xff0c;可用于线性代数计算、图形和动态仿真的…...

基于 Metropolis 的朗之万算法

基于 Metropolis 的朗之万算法 1. 未经调整的朗之万算法2. 基于 Metropolis 的朗之万算法 (MALA)2.1. MH算法2.2. 基于 Metropolis 的朗之万算法 (MALA) 3. Metropolis 调整的朗之万截断算法&#xff08;MALTA&#xff09; 1. 未经调整的朗之万算法 未调整的朗之万算法 (ULA) 是…...

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT&#xff0c;这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频&#xff0c;并利用 SAM 2 进行 3D 空间分割&#xff0c;无需进一步训练或 2D-3D 投影。 我们的框架…...

深入理解FastAPI的response_model:自动化数据验证与文档生成

使用 FastAPI 的 response_model 参数 在构建 RESTful API 时&#xff0c;确保数据的一致性和正确性是非常重要的。FastAPI 提供了强大的工具来帮助开发者实现这一目标。其中一个关键特性是 response_model 参数&#xff0c;它允许开发者定义期望的响应格式&#xff0c;并自动…...

【数据结构与算法 | 灵神题单 | 删除链表篇】力扣3217, 82, 237

总结&#xff0c;删除链表节点问题使用到列表&#xff0c;哈希表&#xff0c;递归比较容易超时&#xff0c;我觉得使用计数排序比较稳&#xff0c;处理起来也不是很难。 1. 力扣3217&#xff1a;从链表中移除在数组中的节点 1.1 题目&#xff1a; 给你一个整数数组 nums 和一…...

快速失败 (fail-fast) 和安全失败 (fail-safe)

1. 定义与工作原理 1.1 快速失败&#xff08;Fail-Fast&#xff09; 定义&#xff1a; 快速失败是一种系统设计原则&#xff0c;当系统遇到异常情况或错误时&#xff0c;立即停止执行并返回错误&#xff0c;而不是试图继续执行或处理潜在的问题。快速失败系统会主动检测系统中…...

【MySQL】MySQL中表的增删改查——(基础篇)(超详解)

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解关于MySQL中CDUD的基础操作&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;http://t.csdnimg.cn/fNldO &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 目录 …...

【B题第二套完整论文已出】2024数模国赛B题第二套完整论文+可运行代码参考(无偿分享)

2024数模国赛B题完整论文 摘要&#xff1a; 随着电子产品制造业的快速发展&#xff0c;质量控制与成本优化问题成为生产过程中亟待解决的核心挑战。为应对生产环节中的质量不确定性及成本控制需求&#xff0c;本文结合抽样检测理论和成本效益分析&#xff0c;通过构建数学模型…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上&#xff0c;所以报错&#xff0c;到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本&#xff0c;cu、torch、cp 的版本一定要对…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...