记一次 SpringBoot 启动慢的问题
记一次 SpringBoot 启动慢的问题
- 背景
- 问题描述
- 分析处理
- Flame Graph 火焰图
- Call Tree 调用树
- 关键词检索
- 尝试解决
- 为什么这样
- 反向检索
- 问题梳理
- 复盘
- 处理流程
- 为什么
- Reference
背景
最近临时接了一个任务,就从一个旧 springboot 项目 copy 出来,临时写个服务,跑一些数据。
项目的基本配置:
- JDK 1.8
- spring boot 2.0.6.RELEASE
- tomcat 9.0.83
- Hibernate 5
- org.postgresql.postgresql-42.2.9 版本
- Postgresql 14.10
项目功能很简单,就是查一批数据,处理一些逻辑。
时间紧任务重,赶紧噼里啪啦开干。
未曾想简单项目也有“鬼”。
问题描述
匆匆忙忙搞完我的 CURD 代码,再拼装一下,点击启动,趁着空档,接个水,上个厕所。
回来了,浏览器 http://localhost:8080 回车, 居然报错了,没有服务???
切换到 IDEA,看一下控制台输出日志,嗯?怎么还没显示 端口号 server start成功呢?
[2025-01-21 10:59:32,931] restartedMain org.hibernate.annotations.common.reflection.java.JavaReflectionManager 66 INFO HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
[2025-01-21 10:59:32,994] restartedMain com.mchange.v2.log.slf4j.Slf4jMLog S l f 4 j M L o g g e r Slf4jMLogger Slf4jMLoggerInfoLogger 212 INFO Initializing c3p0 pool… com.mchange.v2.c3p0.ComboPooledDataSource []
[2025-01-21 10:59:33,276] restartedMain org.hibernate.dialect.Dialect 157 INFO HHH000400: Using dialect: org.hibernate.dialect.PostgreSQL94Dialect
最后一行日志, org.postgresql.Postgresql.Dailet , 好像是 Hibernate 初始化的 SQL 方言。
那就再等一下看看。
好家伙,这一等,足足快5分钟,终于慢悠悠地启动成功。
不应该呀,这么简单的单体 spring boot 项目,连个 PG,处理个数据,要启动5分钟,有没有搞错?
反复重启 2-3次,发现一直卡到那个地方。
以我之前的经验,多半卡在那个 Spring Bean 的初始化上了,而且跟 PG 有关。
上次碰到这个是还是上次呢,依稀记得是 rabbitMQ 初始化,因为网络问题,连接超时后一直连接重试,也是卡了几分钟。
不废话,上工具–照妖镜(Profiler),看看哪里搞鬼。
分析处理
使用 IDEA 自带的 Intellij Profiler,开启路径:
View > Tool > Profiler
main 方法上打断点,启动项目,选中进程,然后在 profiler 中开启监控,断点跳过,让它跑。
等了4-5分钟,关闭监控,关闭服务,开始看看我们抓到了什么。
Flame Graph 火焰图
选中 restartedMain 线程,这个是我们的启动线程,右侧看看火焰图,看哪里耗时多。
注意 右上角切换成 Total Time。

这个栈是真深,我就不截全了。
发现它就是个平顶山,耗时的大头都在最上面。
java.net.SocketInputStream.socketRead0(FileDescriptor, byte[], int, int, int)
一下干到 native 代码了,还能看到 windows 平台的动态链接库,微软的Socket库……
有几个关键路径:
hibernate5 buildSessionFactory
org.postgresql.jdbc.PgDatabaseMetaData.getTypeInfo()
org.postgresql.jdbc.TypeInfoCache.getSQLType(String)
Call Tree 调用树
换个视角看看,切换到 Call Tree 菜单,选中 restartedMain 线程。
spring 容器初始化的栈是真滴深,我只抓出最后一部分,时间单位是毫秒。

PgDatabaseMetaData.getTypeInfo() 执行了 236秒,还没返回,耗时占了整个运行时长的 99.2%, 真无语了。
关键词检索
Google 搜索关键词:postgresql jdbc TypeCache.getSQLType blocked on socket read
扒拉扒拉,没啥有价值的信息。
问题相似,但是没有最终的解决掉:
https://postgrespro.com/list/thread-id/2699119
这个也是类似,最后有提示,可能是驱动版本和 pg 版本不对照
https://confluence.atlassian.com/jirakb/connection-problems-to-postgresql-result-in-stuck-threads-in-jira-1047534091.html
PostgreSQL jdbc driver version
PostgreSQL jdbc 驱动程序版本
The socketTimeout connection property was not enforced properly due to a bug in the driver. Version 42.2.15 (2020-08-14) includes a bug fix:
由于驱动程序中存在错误,因此未正确实施 socketTimeout 连接属性。版本 42.2.15 (2020-08-14) 修复了一个错误:
● “Make sure socketTimeout is enforced PR 1831, 210b27a6” from the PostgreSQL JDBC Driver change log.
“确保强制实施 socketTimeout PR 1831、210b27a6”,来自 PostgreSQL JDBC 驱动程序更改日志。
Additionally, a bug exists in JDBC versions prior to 42.2.19 where SocketTimeoutException was ignored and thus timeout did not work as expected. Version 42.2.19 (2021-02-18) includes a bug fix:
此外,在 42.2.19 之前的 JDBC 版本中存在一个错误,即忽略 SocketTimeoutException,因此超时无法按预期工作。版本 42.2.19 (2021-02-18) 修复了一个错误:
● “properly set cancel socket timeout PR 2044 e551d1a6” from the PostgreSQL JDBC Changelog
“正确设置取消套接字超时 PR 2044e551d1a6”来自 PostgreSQL JDBC 更改日志
Please ensure that version 42.2.19 or later is used to ensure that the socketTimeout connection property works as expected.
请确保使用版本 42.2.19 或更高版本,以确保 socketTimeout 连接属性按预期工作。
得去 github 上 搜搜 issues: QueryExecutorImpl.execute block
看了几个 issue,都没有匹配我的问题
尝试解决
根据检索的信息,以及 PG 的版本和驱动的对应关系,优先调整驱动版本。
pogtgresql 14.10 => 驱动 42.6.X +
从 42.2.9 切换到 42.6.1 版本,重新 build,启动
OK了,启动很顺利。
问题解决了,但是莫名其妙的。
为什么这样
反向检索
肯定是 42.2.9 -> 42.6.1 中间有那个版本修复了这个问题。
没有办法的办法,反向分析,去 release 信息里去看看版本发布的 bug fix。
找到 42.2.10 版本发布信息时,发现了一个 PR:
Fix Network Performance of PgDatabaseMetaData.getTypeInfo() method by @dupski in #1668
修复 PgDatabaseMetaData.getTypeInfo() 方法的网络性能 by in #1668
哦吼,这不是跟我们的调用栈很相似吗?
我们看一下,它是修复的那个 issue:
Retrieving system column data types is slow #1342
https://github.com/pgjdbc/pgjdbc/issues/1342
关键词是 Retrieving system column data types is slow , 这可跟我们的检索词一点都不搭边。
但是内容确实很相似,继续查找,PgDatabaseMetaData.getTypeInfo()
N+1 SELECT caused by PgDatabaseMetaData#getTypeInfo() # 1301
https://github.com/pgjdbc/pgjdbc/issues/1301
这个 issue 跟我们的很像, PgDatabaseMetaData.getTypeInfo() 跑了 4分钟左右才返回。
感兴趣的可以深入看一下。
问题梳理
试着梳理一下,不一定对。
写个 3分钟速食版试着解释一下这个问题:
Hibernate sessionFactory 初始化的时候,会从 JDBC 驱动 的DatabaseMetaData 中提取类型信息。
我是用的是PG库, 驱动对应的是 PgDatabaseMetaData.getTypeInfo() 。
在 PG 中除了基本的列类型外,表也是一种复合类型,包括:视图,函数,序列等。
getTypeInfo 的规范说 get all of the types,所以查所有类型,包括表,视图,函数,序列,类型等元信息。
这个检索动作很慢,驱动程序首先执行 SQL 查询以获取可用类型,然后再循环地为每种类型运行SQL查询,这个地方存在严重的网络性能,会在启动阶段卡死,查询很久。
那么PgDatabaseMetaData.getTypeInfo()查询所有类型信息究竟要返回哪些信息,需要PG驱动实现的时候进行取舍。
42.2.6 版本 PgDatabaseMetaData.getTypeInfo 已经移除了 table类型(包括 表 视图 函数 序列),套用一句维护者的话:
Well I think removing tables from the typecache would help. I can’t imagine a database with 200k types
https://github.com/pgjdbc/pgjdbc/pull/1302
开眼了吧,业务的水也很深的好吧。
42.2.10 版本 优化了 PgDatabaseMetaData.getTypeInfo 的网络性能。
https://github.com/pgjdbc/pgjdbc/pull/1668
优化了类型信息的获取
从 42.2.9 到 42.6.2 版本更新中涉及到 PgDatabaseMetaData.getTypeInfo 只有这两个,所以42.2.10 版本应该能解决我的问题。
PS: 我重新用 42.2.10 版本启动了,6秒完成启动,这个版本也有效
但 PG 跨大版本升级后,会存在一些改动,尤其是元数据的部分,为了避免潜在的坑,还是使用跟 14.10 匹配的版本 42.6.1 吧。
所以使用驱动的时候一定要确定好 DB 的版本与驱动是否匹配。
复盘
处理流程
想起了一句名言:问题的关键是要找到关键的问题。
那么我们是怎么找到和定位这个关键的问题的呢?
启动速度慢,用性能分析工具,对启动耗时进行准确的定位。
定位问题之后,我们是如何处理的?
我是没法直接搞定这个问题,只能查看方法调用栈,快速提取关键词进行检索。
搜索引擎解决问题了吗,有其他方式吗?
搜索引擎没直接解决我们的问题,但是给我们提供了一些思路。
如果无法检索到的话,就需要回到源头,去项目的 github 社区,搜索 issue。
我们的关键词可能无法匹配到 issue,那怎么办?
去 release 发布信息中去查看,可能这个问题已经修复了。
又总结了一个经典处理套路:
有问题的话,升个版试试,说不定新版本已经解决这个问题了。
重启和升版总有一个适合你。
为什么
这个问题本来觉得很简单,只是驱动版本不匹配的问题。
但是为了总结整理,反而挖到了不少知识盲区。
凡是多问个为什么,比别人多想一步,总会有意想不到的收货。
不要老是在水面游泳,偶尔也要扎个猛子,下潜一下,看看不一样的风景。
看了大佬们的 issue 讨论,好像自己也参与了一样,感觉真不错。
Enjoy Code, Enjoy Life.
Reference
N+1 SELECT caused by PgDatabaseMetaData#getTypeInfo()
https://github.com/pgjdbc/pgjdbc/pull/1302
Retrieving system column data types is slow
https://github.com/pgjdbc/pgjdbc/pull/1668
相关文章:
记一次 SpringBoot 启动慢的问题
记一次 SpringBoot 启动慢的问题 背景问题描述分析处理Flame Graph 火焰图Call Tree 调用树关键词检索尝试解决 为什么这样反向检索问题梳理 复盘处理流程为什么 Reference 背景 最近临时接了一个任务,就从一个旧 springboot 项目 copy 出来,临时写个服…...
高效安全文件传输新选择!群晖NAS如何实现无公网IP下的SFTP远程连接
文章目录 前言1. 开启群晖SFTP连接2. 群晖安装Cpolar工具3. 创建SFTP公网地址4. 群晖SFTP远程连接5. 固定SFTP公网地址6. SFTP固定地址连接 前言 随着远程办公和数据共享成为新常态,如何高效且安全地管理和传输文件成为了许多人的痛点。如果你正在寻找一个解决方案…...
如何在Python中进行JSON数据的序列化和反序列化?
在Python中,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。Python内置的json模块提供了简单易用的方法来实现数据的序列化和反序列化。下面将详细介绍如何…...
学习记录-统计记录场景下的Redis写请求合并优化实践
学习记录-使用Redis合并写请求来优化性能 1.业务背景 学习进度的统计功能:为了更精确的记录用户上一次播放的进度,采用的方案是:前端每隔15秒就发起一次请求,将播放记录写入数据库。但问题是,提交播放记录的业务太复杂了&#x…...
网站HTTP改成HTTPS
您不仅需要知道如何将HTTP转换为HTTPS,还必须在不妨碍您的网站自成立以来建立的任何搜索排名权限的情况下进行切换。 为什么应该从HTTP转换为HTTPS? 与非安全HTTP于不同,安全域使用SSL(安全套接字层)服务器上的加密代…...
如何在龙蜥 OS(AliOS)上安装极狐GitLab?
本文分享如何在龙蜥操作系统(AliOS)(包括 RHCK 和 ANCK 两种,两种方式的安装流程一样)上安装极狐GitLab? 前提条件 一个安装了龙蜥操作系统的云服务器 可以查看 /etc/os-release中的信息,确认…...
unity插件Excel转换Proto插件-ExcelToProtobufferTool
unity插件Excel转换Proto插件-ExcelToProtobufferTool **ExcelToProtobufTool 插件文档****1. 插件概述****2. 默认配置类:DefaultIProtoPathConfig****属性说明** **3. 自定义配置类****定义规则****示例代码** **4. 使用方式****4.1 默认路径****4.2 自定义路径**…...
C#中的语句
C#提供了各式各样的语句,大多数是由C和C发展而来,当然,在C#中做了相应修改。语句和表达式一样,都是C#程序的基本组成部分,在本文我们来一起学习C#语句。 1.语句 语句是构造所有C#程序的过程构造块。在语句中可以声明…...
《罗宾逊-旅途VR》Build2108907官方学习版
《罗宾逊-旅途VR》官方版 https://pan.xunlei.com/s/VODiY5gn_fNxKREdVRdwVboCA1?pwdsh3f# 从第一人称的角度进行探索,玩家将遇到一系列恐龙和生物,这些恐龙和生物会对它们在泰森三世生态系统中的存在做出反应。强调与周围环境的互动,鼓励玩…...
常用的跨域方案有哪些?
在前端开发中,跨域(Cross-Origin)是一个常见问题,通常是由于浏览器的同源策略(Same-Origin Policy)限制导致的。为了解决跨域问题,前端开发者可以采用多种方案。 1. CORS(跨域资源共…...
JDBC实验测试
一、语言和环境 实现语言:Java。 环境要求:IDEA2023.3、JDK 17 、MySQL8.0、Navicat 16 for MySQL。 二、技术要求 该系统采用 SWING 技术配合 JDBC 使用 JAVA 编程语言完成桌面应用开发。 三、功能要求 某电商公司为了方便客服查看用户的订单信…...
ChatGPT 摘要,以 ESS 作为你的私有数据存储
作者:来自 Elastic Ryan_Earle 本教程介绍如何设置 Elasticsearch 网络爬虫,将网站索引到 Elasticsearch 中,然后利用 ChatGPT 使用我们的私人数据来总结对其提出的问题。 Python 脚本的 Github Repo:https://github.com/Gunner…...
每日一题洛谷P2669 [NOIP2015 普及组] 金币c++
#include<iostream> using namespace std; int main() {int k;cin >> k;int sum 0;int n 1;while (k > 0) {sum n * n;k - n;n;}sum k * (n - 1);cout << sum << endl;return 0; }...
【C语言系列】深入理解指针(2)
一、数组名的理解 上一篇文章中我们写过一个这样的代码: int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0];这里使用&arr[0] 的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,而且是数组首元素的地址ÿ…...
与 Spring Boot 的无缝集成:ShardingSphere 快速集成实践
ShardingSphere 是一个轻量级的开源分布式数据库中间件,它支持分库分表、分布式事务、读写分离等功能。它能够与各种应用框架进行集成,其中与 Spring Boot 的集成非常流行,因为它能够帮助开发者在 Spring Boot 项目中快速实现高性能的分布式数…...
【QT】窗口/界面置于最前端显示,且激活该窗口
目录 0.环境 1.问题描述 2.具体实现 0.环境 windows11 qt 1.问题描述 我有一个窗口QMainWindow(也适用于QWidget或QDialog),想让其在显示的时候置于最前面,且激活成为当前活动窗口 2.具体实现 mainWindow->show();mainWind…...
DOL-288 多功能电子计时器说明书
新买一个计时器,它的用法不太直观,所以把说明书留在这里,以便以后查询。 DOL-288 多功能电子计时器说明书 1.功能说明: 正计时功能,计时上限为23小时59分59秒倒计时功能,计时上限为23小时59分59秒&#…...
14 常用的负载均衡算法
基于nginx的代理 1. 轮询算法 例如我们在nginx服务器中代理了3台服务器,再每次客户端发起请求的时候按照顺序请求挨次的发送到代理的三台服务器上。该算法比较适合每台服务器性能差不多的场景,如果部分服务器性能比较差,可能会造成性能好的…...
方法建议ChatGPT提示词分享
方法建议 ChatGPT能够根据您的具体需求提供针对性的建议,帮助您选择最合适的研究方法。通过清晰的提示,ChatGPT可以精准地为您提供最契合的研究方案。此外,它还能协助您将这些方法灵活地应用于新的研究环境,提出创新的技术解决方案…...
如何提高自动化测试覆盖率和效率
用ChatGPT做软件测试 在现代软件开发中,自动化测试已经成为保证软件质量的重要手段。然而,在实践中,自动化测试的覆盖率和效率常常受到限制,导致潜在缺陷未能及时发现或测试资源浪费。因此,提升自动化测试的覆盖率和效…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
