缓存预热!真香

预热一般指缓存预热,一般用在高并发系统中,为了提升系统在高并发情况下的稳定性的一种手段。

缓存预热是指在系统启动之前或系统达到高峰期之前,通过预先将常用数据加载到缓存中,以提高缓存命中率和系统性能的过程。缓存预热的目的是尽可能地避免缓存击穿和缓存雪崩,还可以减轻后端存储系统的负载,提高系统的响应速度和吞吐量。
 

预热的必要性


缓存预热的好处有很多,如:

  1. 减少冷启动影响:当系统重启或新启动时,缓存是空的,这被称为冷启动。冷启动可能导致首次请求处理缓慢,因为数据需要从慢速存储(如数据库)检索。

  2. 提高数据访问速度:通过预先加载常用数据到缓存中,可以确保数据快速可用,从而加快数据访问速度。

  3. 平滑流量峰值:在流量高峰期之前预热缓存可以帮助系统更好地处理高流量,避免在流量激增时出现性能下降。

  4. 保证数据的时效性:定期预热可以保证缓存中的数据是最新的,特别是对于高度依赖于实时数据的系统。

  5. 减少对后端系统的压力:通过缓存预热,可以减少对数据库或其他后端服务的直接查询,从而减轻它们的负载。

预热的方法

缓存预热的一般做法是在系统启动或系统空闲期间,将常用的数据加载到缓存中,主要做法有以下几种:

系统启动时加载:在系统启动时,将常用的数据加载到缓存中,以便后续的访问可以直接从缓存中获取。

定时任务加载:定时执行任务,将常用的数据加载到缓存中,以保持缓存中数据的实时性和准确性。

手动触发加载:在系统达到高峰期之前,手动触发加载常用数据到缓存中,以提高缓存命中率和系统性能。

用时加载:在用户请求到来时,根据用户的访问模式和业务需求,动态地将数据加载到缓存中。

缓存加载器:一些缓存框架提供了缓存加载器的机制,可以在缓存中不存在数据时,自动调用加载器加载数据到缓存中。

Redis预热

在分布式缓存中,我们通常都是使用Redis,针对Redis的预热,有以下几个工具可供使用,帮助我们实现缓存的预热:

RedisBloom:RedisBloom是Redis的一个模块,提供了多个数据结构,包括布隆过滤器、计数器、和TopK数据结构等。其中,布隆过滤器可以用于Redis缓存预热,通过将预热数据添加到布隆过滤器中,可以快速判断一个键是否存在于缓存中。

Redis Bulk loading:这是一个官方出的,基于Redis协议批量写入数据的工具

Redis Desktop Manager:Redis Desktop Manager是一个图形化的Redis客户端,可以用于管理Redis数据库和进行缓存预热。通过Redis Desktop Manager,可以轻松地将预热数据批量导入到Redis缓存中。

应用启动时预热

ApplicationReadyEvent

在应用程序启动时,可以通过监听应用启动事件,或者在应用的初始化阶段,将需要缓存的数据加载到缓存中。

ApplicationReadyEvent 是 Spring Boot 框架中的一个事件类,它表示应用程序已经准备好接收请求,即应用程序已启动且上下文已刷新。这个事件是在 ApplicationContext 被初始化和刷新,并且应用程序已经准备好处理请求时触发的。

基于ApplicationReadyEvent,我们可以在应用程序完全启动并处于可用状态后执行一些初始化逻辑。使用 @EventListener 注解或实现 ApplicationListener 接口来监听这个事件。例如,使用 @EventListener 注解:

@EventListener(ApplicationReadyEvent.class)
public void preloadCache() {// 在应用启动后执行缓存预热逻辑// ...
}

Runner

如果你不想直接监听ApplicationReadyEvent,在SpringBoot中,也可以通过CommandLineRunner 和 ApplicationRunner 来实现这个功能。

CommandLineRunner 和 ApplicationRunner 是 Spring Boot 中用于在应用程序启动后执行特定逻辑的接口。这解释听上去就像是专门干这个事儿的。

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;@Component
public class MyCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) throws Exception {// 在应用启动后执行缓存预热逻辑// ...}
}

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;@Component
public class MyApplicationRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) throws Exception {// 在应用启动后执行缓存预热逻辑// ...}

}

CommandLineRunner 和 ApplicationRunner的调用,是在SpringApplication的run方法中

其实就是callRunners(context, applicationArguments);的实现:

private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList<>();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());AnnotationAwareOrderComparator.sort(runners);for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}
}

使用InitializingBean接口

实现 InitializingBean 接口,并在 afterPropertiesSet 方法中执行缓存预热的逻辑。这样,Spring 在初始化 Bean 时会调用 afterPropertiesSet 方法。

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;@Component
public class CachePreloader implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {// 执行缓存预热逻辑// ...}
}

这个方法的调用我们在Spring的启动流程中也介绍过,不再展开了

使用@PostConstruct注解

类似的,我们还可以使用 @PostConstruct 注解标注一个方法,该方法将在 Bean 的构造函数执行完毕后立即被调用。在这个方法中执行缓存预热的逻辑。

import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;@Component
public class CachePreloader {@PostConstructpublic void preloadCache() {// 执行缓存预热逻辑// ...}
}

定时任务预热

在启动过程中预热有一个问题,那就是一旦启动之后,如果需要预热新的数据,或者需要修改数据,就不支持了,那么,在应用的运行过程中,我们也是可以通过定时任务来实现缓存的更新预热的。

我们通常依赖这种方式来确保缓存中的数据是最新的,避免因为业务数据的变化而导致缓存数据过时。

在Spring中,想要实现一个定时任务也挺简单的,基于@Scheduled就可以轻易实现.

@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
public void scheduledCachePreload() {// 执行缓存预热逻辑// ...
}

也可以依赖xxl-job等定时任务实现。

缓存器预热

些缓存框架提供了缓存加载器的机制,可以在缓存中不存在数据时,自动调用加载器加载数据到缓存中。这样可以简化缓存预热的逻辑。如Caffeine中就有这样的功能:

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;@Service
public class MyCacheService {private final LoadingCache<String, String> cache;public MyCacheService() {this.cache = Caffeine.newBuilder().refreshAfterWrite(1, TimeUnit.MINUTES)  // 配置自动刷新,1分钟刷新一次.build(key -> loadDataFromSource(key));  // 使用加载器加载数据}public String getValue(String key) {return cache.get(key);}private String loadDataFromSource(String key) {// 从数据源加载数据的逻辑// 这里只是一个示例,实际应用中可能是从数据库、外部服务等获取数据System.out.println("Loading data for key: " + key);return "Value for " + key;}
}

在上面的例子中,我们使用 Caffeine.newBuilder().refreshAfterWrite(1, TimeUnit.MINUTES) 配置了缓存的自动刷新机制,即每个缓存项在写入后的1分钟内,如果有读请求,Caffeine 会自动触发数据的刷新。

loadDataFromSource 方法是用于加载数据的自定义方法。你可以在这个方法中实现从数据源(例如数据库、外部服务)加载数据的逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/680947.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java程序设计】【C00251】基于Springboot的医院信息管理系统(有论文)

基于Springboot的医院信息管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的医院信管系统 本系统分为管理员功能模块、系统功能模块以及医生功能模块。 系统功能模块&#xff1a;医院信管系统&#xff0c;…

161基于matlab的快速谱峭度方法

基于matlab的快速谱峭度方法&#xff0c;选择信号峭度最大的频段进行滤波&#xff0c;对滤波好信号进行包络谱分析。输出快速谱峭度及包络谱结果。程序已调通&#xff0c;可直接运行。 161 信号处理 快速谱峭度 包络谱分析 (xiaohongshu.com)

09-OpenFeign-令牌中继、透传

在一般发送请求的过程中&#xff0c;我们会在请求Header中添加参数信息&#xff0c;如token认证、全局事物id、链路追踪的logid等。 但是使用openfeign后&#xff0c;默认不支持传递header头信息。 因此&#xff0c;需要借助额外的配置&#xff0c;让请求的Header中的参数令牌…

C++初阶之类与对象(中)——六个默认函数详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言进阶 数据结构初阶 Linux C初阶 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力&#xff0c;一起奔赴大厂 目录 一.前言 二.构造函数 2.1构造函数的语法和特性 2.1.1语法 2.…

Blender教程(基础)-顶点合并-18

一、常规合并 准备&#xff0c;新建一个圆环8个点、全选顶点采用F填充&#xff0c;采用J链接多个顶点如下图所示图形。 选择其中一个顶点 按字母GG、移动到离另外一个顶点更近。再选中两个顶点&#xff0c;右键弹出合并顶点>到中心 二、重叠合并 回退回去 按字母G…

飞机大作战(c语言)

前言&#xff1a; 飞机大作战游戏是一种非常受欢迎的射击类游戏&#xff0c;玩家需要控制一架战斗机在屏幕上移动&#xff0c;击落敌机以获得分数。本游戏使用C语言编写&#xff0c;旨在帮助初学者了解游戏开发的基本概念和技巧。 在开始编写代码之前&#xff0c;我们需要先了…

LocalAI 部署(主要针对 mac m2 启动)

LocalAI 部署 介绍 LocalAI 是免费的开源 OpenAI 替代方案。 LocalAI 充当 REST API 的直接替代品&#xff0c;与本地推理的 OpenAI API 规范兼容。 它无需 GPU&#xff0c;还有多种用途集成&#xff0c;允许您使用消费级硬件在本地或本地运行 LLM、生成图像、音频等等&#…

第二节:轻松玩转书生·浦语大模型趣味Demo

参考教程&#xff1a;https://github.com/InternLM/tutorial/blob/main/helloworld/hello_world.md InternLM-Chat-7B 智能对话 Demo 终端运行 web demo 运行 1.首先启动服务&#xff1a; cd /root/code/InternLM streamlit run web_demo.py --server.address 127.0.0.1 --…

普京警告:美元大衰落

来源&#xff1a;Bitcoin.com 编译/作者&#xff1a;秦晋 美元不仅是全球储备货币&#xff0c;也是美国用来维护全球权力的重要武器。甚至还是衡量比特币市值与价格的重要指标之一。比特币富豪的财富指标某种程度上也是通过美元多少来进行衡量的。 2月9日&#xff0c;俄罗斯总统…

66.加一

66. 加一 给定一个由 整数 组成的 非空 数组所表示的非负整数&#xff0c;在该数的基础上加一。 最高位数字存放在数组的首位&#xff0c; 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外&#xff0c;这个整数不会以零开头。 示例 1&#xff1a; 输入&#xff…

(免费领源码)java+SSM+mysql 大学食堂订餐系统APP 75418-计算机毕业设计项目选题推荐

摘 要 本论文主要论述了如何使用SSM框架开发一个大学食堂订餐系统APP&#xff0c;将严格按照软件开发流程进行各个阶段的工作&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述大学食堂订餐系统APP的当前背景以及系统开发的目的&#xff0c;后续章节将…

一、Docker部署MySQL

Docker部署MySQL 一、安装Docker二、拉取MySQL镜像1.选择拉取版本2.拉取镜像 三、启动MySQL1.确定好挂载目录2.启动3.查看是否启动4.开启远程访问权限 一、安装Docker 安装教程&#xff1a;https://qingsi.blog.csdn.net/article/details/131270071 二、拉取MySQL镜像 1.选择…

双指针练习题复写零

复写零 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改&#xff0c;不要从函数返回任何东西。 示例 1&…

【JavaEE进阶】 利用Spring简单实现加法计算器和用户登录

文章目录 &#x1f38d;序言&#x1f333;加法计算器&#x1f6a9;准备工作&#x1f6a9;约定前后端交互接⼝&#x1f332;后端服务器代码的书写 &#x1f334;用户登录&#x1f6a9;效果展示&#x1f6a9;准备工作&#x1f6a9;约定前后端交互接⼝&#x1f388;需求分析&#…

JavaI/O流 File类(目录)

目录 File类目录操作实例 File类目录操作 Java的File类提供了对文件和目录进行操作的方法。对于目录&#xff0c;File类提供了以下一些方法&#xff1a; 判断目录是否存在&#xff1a;使用exists()方法可以判断目录是否存在。创建目录&#xff1a;使用mkdir()或mkdirs()方法可…

16 贪吃蛇

目录 游戏背景游戏效果展示基本功能技术要点WIN32 API介绍设计与分析实现参考代码 1. 游戏背景 贪吃蛇是久负盛名的游戏&#xff0c;是一款经典游戏 2. 效果展示 3. 基本功能 使用c语言在windows环境的控制台模拟实现小游戏贪吃蛇 基本的功能&#xff1a; 地图绘制吃食物上…

题记(40)--二次方程计算器

目录 一、题目内容 二、输入描述 三、输出描述 四、输入输出示例 五、完整C语言代码 一、题目内容 设计一个二次方程计算器 二、输入描述 每个案例是关于x的一个二次方程表达式&#xff0c;为了简单&#xff0c;每个系数都是整数形式。 三、输出描述 每个案例输出两个实数…

MIT-Missing Semester_Topic 3:Editors (Vim) 练习题

文章目录 练习一练习二练习三练习四练习五练习六练习七练习八 本 Topic 的 MIT 讲解网页&#xff08;练习题未给解答&#xff09; 练习一 自行完成 vimtutor。vimtutor 是 Vim 本身附带的一个入门教程&#xff0c;在 shell 中直接输入 vimtutor 便能运行。注意该教程在 8024 大…

[ubuntu]split命令分割文件

split 命令 $ split --help Usage: split [OPTION]... [INPUT [PREFIX]] Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default size is 1000 lines, and default PREFIX is x. With no INPUT, or when INPUT is -, read standard input.Mandatory argume…

千里马平台设计说明-字典缓存

字典是软件开发中常用的功能。使用字典的核心问题是翻译&#xff0c;因为数据库中存储的是代码&#xff0c;前台页面展示的是描述。用于多语言环境时&#xff0c;翻译过程还需要根据语言环境进行适配。为了加快字典的加载速度&#xff0c;千里马平台采用了后台缓存前台缓存2级缓…