项目实践缓存预热方案之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

相关文章

Django调用外部Python程序的完整项目实战

《Django调用外部Python程序的完整项目实战》Django是一个强大的PythonWeb框架,它的设计理念简洁优雅,:本文主要介绍Django调用外部Python程序的完整项目实战,文中通... 目录一、为什么 Django 需要调用外部 python 程序二、三种常见的调用方式方式 1:直接 im

jdk1.8的Jenkins安装配置实践

《jdk1.8的Jenkins安装配置实践》Jenkins是一款流行的开源持续集成工具,支持自动构建、测试和部署,通过Jenkins,开发团队可以实现代码提交后自动进行构建、测试,并将构建结果分发到测... 目录Jenkins介绍Jenkins环境搭建Jenkins安装配置Jenkins插件安装Git安装配

SpringBoot的全局异常拦截实践过程

《SpringBoot的全局异常拦截实践过程》SpringBoot中使用@ControllerAdvice和@ExceptionHandler实现全局异常拦截,@RestControllerAdvic... 目录@RestControllerAdvice@ResponseStatus(...)@Except

mysql_mcp_server部署及应用实践案例

《mysql_mcp_server部署及应用实践案例》文章介绍了在CentOS7.5环境下部署MySQL_mcp_server的步骤,包括服务安装、配置和启动,还提供了一个基于Dify工作流的应用案例... 目录mysql_mcp_server部署及应用案例1. 服务安装1.1. 下载源码1.2. 创建独立

C#高效实现在Word文档中自动化创建图表的可视化方案

《C#高效实现在Word文档中自动化创建图表的可视化方案》本文将深入探讨如何利用C#,结合一款功能强大的第三方库,实现在Word文档中自动化创建图表,为你的数据呈现和报告生成提供一套实用且高效的解决方... 目录Word文档图表自动化:为什么选择C#?从零开始:C#实现Word文档图表的基本步骤深度优化:C

SpringBoot简单整合ElasticSearch实践

《SpringBoot简单整合ElasticSearch实践》Elasticsearch支持结构化和非结构化数据检索,通过索引创建和倒排索引文档,提高搜索效率,它基于Lucene封装,分为索引库、类型... 目录一:ElasticSearch支持对结构化和非结构化的数据进行检索二:ES的核心概念Index:

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

JAVA项目swing转javafx语法规则以及示例代码

《JAVA项目swing转javafx语法规则以及示例代码》:本文主要介绍JAVA项目swing转javafx语法规则以及示例代码的相关资料,文中详细讲解了主类继承、窗口创建、布局管理、控件替换、... 目录最常用的“一行换一行”速查表(直接全局替换)实际转换示例(JFramejs → JavaFX)迁移建

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加