项目实践缓存预热方案之CommandLineRunner和ApplicationRunner

本文主要是介绍项目实践缓存预热方案之CommandLineRunner和ApplicationRunner,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

众所周知,在项目的开发中,合理使用缓存是提高服务性能的一大利器,本篇文章就来介绍一下我所在项目中如何使用缓存的一个案例。

背景

我们的项目是由多个微服务所组成,业务是保险,我所负责的模块是出单,在压测的过程中,发现当所有服务启动好之后,第一次出单的时间存在耗时较长的情况,通过sleuth分析了一下各个服务之间的调用链,针对第一单,发现出单接口中存在调用其他接口做查询和逻辑处理,在第一次调用后会将结果缓存,那么以后的调用基本是直接走缓存,不会去和数据库交互,减少了数据库创建和关闭连接之类的耗时。此时,我发现针对首单慢的问题,主要是因为一些接口返回固定的值,第一次没有通过缓存获取而导致的耗时较长的问题。

解决方案

为了解决首单耗时较长的问题,我采用了缓存预热的方案,那就是在服务启动的时候进行缓存预热,这样首单中一些接口的调用也是会通过缓存来取值,肯定是可以减少耗时,提高接口的性能,缩短出单的时间。

缓存预热

  • 不是所有的接口都需要进行缓存预热,应该按照自己的业务所需对缓存预热谨慎使用
  • 对缓存预热应该是同步还是异步进行,这个需要考虑
    • 缓存预热同步,那么服务启动好之后缓存预热也结束了,正常的业务就可以开始进行
    • 缓存预热异步,服务虽然启动好了,但是缓存预热可能还在进行中,是否会影响到自己的业务需要考虑一下
    • 相对比较而言,同步预热会拉长服务的启动时间,异步预热不会拉长服务的启动时间
项目实践

具体的相关代码如下所示:

package com.xxx.xxx.xx.xxx.service.inner.impl;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.util.List;import static java.util.stream.Collectors.toList;/*** xxx 服务启动时 加载缓存  缓存项为vvv的内容* @author xxx*/
@Order(4)
@Component
@Slf4j
public class InitMarketCacheService implements CommandLineRunner {@Value("#{'${zz.xx.goodsId}'.split(',')}")private List<String> aaaArray;@Value("#{'${zz.xx.planId}'.split(',')}")private List<String>  bbbArray;@Value("#{'${zz.xx.productId}'.split(',')}")private List<String>  cccArray;@Autowiredprivate AxxService axxShareService;@Autowiredprivate BxxShareService bxxShareService;@Overridepublic void run(String... args) throws Exception {List<Long> goodsIdList = goodsIdArray.stream().map(Long::valueOf).collect(toList());List<Long> goodsPlanIdList = planIdArray.stream().map(Long::valueOf).collect(toList());List<Long> productIdList = productIdArray.stream().map(Long::valueOf).collect(toList());log.warn("begin init xxservice cache");try {for (Long goodsId:goodsIdList){AxxService.queryGoods(goodsId);}for (Long planId:goodsPlanIdList){AxxService.queryPlanAndPackage(planId);}for (Long productId:productIdList){BxxShareService.detail(productId);}}catch (Exception e){log.error("cache warm up failed",e);}finally {log.warn("end init xxx service cache");}}
}
相关知识点说明

CommandLineRunner

源码如下:

package org.springframework.boot;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;public interface CommandLineRunner {void run(String... args) throws Exception;
}

ApplicationRunner

package org.springframework.boot;import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;public interface ApplicationRunner {void run(ApplicationArguments args) throws Exception;
}

CommandLineRunnerApplicationRunner

  • 区别:
    • CommandLineRunnerrun方法的参数是一个可变参数列表
    • ApplicationRunnerrun方法的参数是一个ApplicationArguments类型的参数
  • 共同点:
    • 都是一个接口interface
    • 里面都有一个run()方法,返回值为void
    • 所有实现这两个接口的Beanspring boot启动后会自动调用
    • 可以定义多个Bean实现接口,但是调用的顺序可以使用@Order注解来指定,其中value属性的值越小,则会优先被调用
注意点

实现这两个接口的类,在执行run方法的时候默认是通过主线程的,如果在服务调用的时候,某个服务异常,那么该服务就会启动不起来,为了不影响服务的正常启动,我们可以采用try...catch的方法对执行run时的异常进行捕获,这样就不会影响服务的正常启动。

在这里插入图片描述

这篇关于项目实践缓存预热方案之CommandLineRunner和ApplicationRunner的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1095600

相关文章

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二