欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot首筆交易慢問題排查與優(yōu)化方案

 更新時間:2025年04月07日 15:19:13   作者:MrWho  
在我們的微服務項目中,遇到這樣的問題:應用啟動后,第一筆交易響應耗時高達4、5秒,而后續(xù)請求均能在毫秒級完成,這不僅觸發(fā)監(jiān)控告警,也極大影響了用戶體驗,本文將結(jié)合日志排查、性能工具分析以及預熱優(yōu)化手段,總結(jié)出一套完整的排查思路和解決方案

問題背景

在我們的微服務系統(tǒng)中,首筆交易響應明顯偏慢,經(jīng)過初步排查發(fā)現(xiàn):

  • Flowable 流程部署、Redis 連接建立、PageHelper 代理生成和 Hibernate Validator 校驗等操作均集中在首筆交易時進行;
  • 后續(xù)交易響應迅速,說明業(yè)務邏輯本身并無性能瓶頸,而主要問題出在各類資源的首次初始化上。

這種“懶加載”機制雖然能夠延遲資源加載,但在首筆交易時往往會導致嚴重延時,影響整體體驗。實際項目中需平衡啟動速度與首次響應效率,主動預熱關(guān)鍵組件。

排查步驟

1. 日志分析

首先,將日志級別調(diào)為 DEBUG,詳細觀察首筆交易與后續(xù)交易之間的差異。
在 Flowable 工作流啟動時,日志中會出現(xiàn)如下部署信息:

2025-03-31-15:24:25:326 [thread1] DEBUG o.f.e.i.bpmn.deployer.BpmnDeployer.deploy.72 -- Processing deployment SpringBootAutoDeployment
2025-03-31-15:24:25:340 [thread1] DEBUG o.f.e.i.b.d.ParsedDeploymentBuilder.build.54 -- Processing BPMN resource E:\gitProjects\flowableProject\target\classes\processes\eib.bpmn20.xml

同樣,Redis 連接在首次調(diào)用時會看到大量lettuce包日志,如:

2025-03-31-15:24:23:587 [XNIO-1 task-1] DEBUG io.lettuce.core.RedisClient.initializeChannelAsync0.304 -- Connecting to Redis at 10.240.75.250:7379

這些信息表明,在首次調(diào)用時,系統(tǒng)才開始部署流程、建立 Redis 連接以及加載其它第三方組件,從而導致延遲。

2. 性能工具定位

由于單純依賴日志排查比較繁瑣,我們還使用了 Java VisualVM(JDK 自帶工具,也可選擇其它工具)進行采樣分析。
在 VisualVM 中選擇目標進程后通過 CPU 取樣,示意圖如下(也可配置JMX遠程連接)。

觀察結(jié)果如下:

發(fā)現(xiàn)首筆交易相比后續(xù)交易多出以下方法的調(diào)用(省略的部分二方包慢代碼):

  • com.github.pagehelper.dialect.auto.DataSourceAutoDialect.<init>
  • org.hibernate.validator.internal.engine.ValidatorImpl.validate()

這些方法的初始化也成為首筆交易慢的原因之一。

優(yōu)化方案:提前預熱各種資源

針對上述問題,我們的優(yōu)化思路很簡單:提前初始化各項資源,確保首筆交易時不再觸發(fā)大量懶加載。為此,我們將所有預熱操作改寫成基于 ApplicationRunner 的實現(xiàn),保證在 Spring Boot 啟動后就自動執(zhí)行。

1. Flowable 流程部署預熱

在應用啟動時,通過掃描 BPMN 文件提前部署流程,避免在交易中首次部署導致延遲。

import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.DeploymentBuilder;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;

@Component
public class ProcessDeploymentRunner implements ApplicationRunner {

    private final RepositoryService repositoryService;

    public ProcessDeploymentRunner(RepositoryService repositoryService) {
        this.repositoryService = repositoryService;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 掃描 processes 目錄下的所有 BPMN 文件
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("classpath:/processes/*.bpmn20.xml");

        if (resources.length == 0) {
            System.out.println("未在 processes 目錄下找到 BPMN 文件");
            return;
        }

        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                .name("自動部署流程");

        for (Resource resource : resources) {
            deploymentBuilder.addInputStream(resource.getFilename(), resource.getInputStream());
        }

        deploymentBuilder.deploy();
        System.out.println("流程定義已部署,數(shù)量:" + resources.length);
    }
}

2. Redis 連接預熱

利用 ApplicationRunner 發(fā)送一次 PING 請求,提前建立 Redis 連接,避免首筆交易時因連接建立而耗時。

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisWarmupRunner implements ApplicationRunner {

    private final StringRedisTemplate redisTemplate;

    public RedisWarmupRunner(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void run(ApplicationArguments args) {
        try {
            String pingResult = redisTemplate.getConnectionFactory().getConnection().ping();
            System.out.println("? Redis connection pre-warmed successfully: " + pingResult);
        } catch (Exception e) {
            System.err.println("? Redis warm-up failed: " + e.getMessage());
        }
    }
}

3. PageHelper 預熱

通過執(zhí)行一條簡單的查詢語句,觸發(fā) PageHelper 及相關(guān) MyBatis Mapper 的初始化。

import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class PageHelperWarmupRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        try {
            boolean result = SqlRunner.db().selectObjs("SELECT 1").size() > 0;
            System.out.println("? PageHelper & SqlRunner pre-warm completed, result: " + result);
        } catch (Exception e) {
            System.err.println("? PageHelper pre-warm failed: " + e.getMessage());
        }
    }
}

(請確保配置文件中已開啟 SQL Runner 功能:
mybatis-plus.global-config.enable-sql-runner=true

4. Hibernate Validator 預熱

通過一次 dummy 校驗操作,提前加載 Hibernate Validator 相關(guān)類和反射邏輯

import jakarta.validation.Validation;
import jakarta.validation.Validator;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class ValidatorWarmupRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        try {
            Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
            DummyEntity dummy = new DummyEntity();
            validator.validate(dummy);
            System.out.println("? Hibernate Validator pre-warm completed!");
        } catch (Exception e) {
            System.err.println("? Hibernate Validator pre-warm failed: " + e.getMessage());
        }
    }

    private static class DummyEntity {
        @jakarta.validation.constraints.NotNull
        private String name;
    }
}

5. Undertow 預熱(可選)

如果使用 Undertow 作為內(nèi)嵌服務器,也可以通過主動發(fā)送 HTTP 請求預熱相關(guān)資源。此外,在配置文件中開啟過濾器提前初始化也有助于降低延遲。

在 application.yml 中設(shè)置:

server:
  undertow:
    eager-init-filters: true

再通過下面的代碼發(fā)送一次預熱請求:

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
public class UndertowWarmupRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        try {
            RestTemplate restTemplate = new RestTemplate();
            String response = restTemplate.getForObject("http://localhost:8080/health", String.class);
            System.out.println("? Undertow pre-warm completed, response: " + response);
        } catch (Exception e) {
            System.err.println("? Undertow pre-warm failed: " + e.getMessage());
        }
    }
}

總結(jié)

通過上述方案,我們將 Flowable 流程部署、Redis 連接、PageHelper 初始化、Hibernate Validator 校驗和 Undertow 相關(guān)組件的預熱操作全部遷移到 ApplicationRunner 中,在應用啟動后就自動執(zhí)行。這樣,首筆交易時不再需要進行大量初始化工作,各項資源已預先加載,確保后續(xù)請求能達到毫秒級響應,大大提升了用戶體驗并避免了無效的監(jiān)控告警。

以上就是SpringBoot首筆交易慢問題排查與優(yōu)化方案的詳細內(nèi)容,更多關(guān)于SpringBoot首筆交易慢問題的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java使用PDFBox實現(xiàn)操作PDF文檔

    Java使用PDFBox實現(xiàn)操作PDF文檔

    這篇文章主要為大家詳細介紹了Java如何使用PDFBox實現(xiàn)操作PDF文檔,例如添加本地圖片、添加網(wǎng)絡(luò)圖片、圖片寬高自適應、圖片水平垂直居中對齊等功能,需要的可以了解下
    2024-03-03
  • 淺談SpringBoot項目如何讓前端開發(fā)提高效率(小技巧)

    淺談SpringBoot項目如何讓前端開發(fā)提高效率(小技巧)

    這篇文章主要介紹了淺談SpringBoot項目如何讓前端開發(fā)提高效率(小技巧),主要介紹了Swagger和Nginx提高效率的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • java書店系統(tǒng)畢業(yè)設(shè)計 用戶模塊(3)

    java書店系統(tǒng)畢業(yè)設(shè)計 用戶模塊(3)

    這篇文章主要介紹了java書店系統(tǒng)畢業(yè)設(shè)計,第三步系統(tǒng)總體設(shè)計,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Java編程求二叉樹的鏡像兩種方法介紹

    Java編程求二叉樹的鏡像兩種方法介紹

    這篇文章主要介紹了Java編程求二叉樹的鏡像兩種方法介紹,分享了兩種方法,遞歸與非遞歸,每種方法又分別介紹了兩種解決思路,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • mybatis不加@Parm注解報錯的解決方案

    mybatis不加@Parm注解報錯的解決方案

    這篇文章主要介紹了mybatis不加@Parm注解報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • springBoot動態(tài)加載jar及如何將類注冊到IOC

    springBoot動態(tài)加載jar及如何將類注冊到IOC

    在SpringBoot項目中動態(tài)加載jar文件并將其類注冊到IOC容器是一種高級應用方式,,這種方法為SpringBoot項目提供了更靈活的擴展能力,使得項目可以在不修改原有代碼的基礎(chǔ)上增加新的功能模塊,感興趣的朋友一起看看吧
    2024-11-11
  • Spring實現(xiàn)資源的動態(tài)加載和卸載的方法小結(jié)

    Spring實現(xiàn)資源的動態(tài)加載和卸載的方法小結(jié)

    這篇文章主要介紹了Spring實現(xiàn)資源的動態(tài)加載和卸載的方法小結(jié),文中通過代碼示例講解的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-06-06
  • xxl-job對比ElasticJob使用示例詳解

    xxl-job對比ElasticJob使用示例詳解

    這篇文章主要為大家介紹了xxl-job對比ElasticJob使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Java中LinkedHashSet的實現(xiàn)原理詳解

    Java中LinkedHashSet的實現(xiàn)原理詳解

    這篇文章主要介紹了Java中LinkedHasSet的實現(xiàn)原理詳解,LinkedHashSet?是具有可預知迭代順序的?Set?接口的哈希表和鏈接列表實現(xiàn),此實現(xiàn)與HashSet?的不同之處在于,后者維護著一個運行于所有條目的雙重鏈接列表,需要的朋友可以參考下
    2023-09-09
  • IDEA一致卡在build時間過長問題解決

    IDEA一致卡在build時間過長問題解決

    有很多小伙伴在起項目的時候巨慢,特別影響開發(fā)效率,本文主要介紹了IDEA一致卡在build時間過長問題解決,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06

最新評論