本文摘要开启虚拟线程后线程告警消失HikariCP 连接池超时却更早出现。先用 JFR 事件排除synchronized阻塞再按并发预算重算连接池容量。一、问题与结论凌晨告警http-nio-8080-exec-*200 个处理线程全部阻塞接口排队日志反复出现HikariCP - Connection is not available, request timed out after 30000ms。团队提议打开spring.threads.virtual.enabled但上线前必须先分清一件事——瓶颈是线程不够还是连接池不够。结论先摆三条200 线程跑满的告警内容其实是「下游资源不足以支撑当前并发」换线程模型只会把这个告警换个位置报出来。虚拟线程把并发上限从线程数搬到了下游最小资源池HikariCP 的maximumPoolSize往往就是那个最小的池它会取代线程池成为新的串行点。JDK 21 上synchronized确实会 pin 住 carrier 线程但它不是连接池超时的默认解释必须靠 JFR 事件取证不能靠猜。二、排查与选择依据按顺序做三步每步先给结论再给证据。第一步确认超时来自池容量而不是线程排队。给spring.datasource.hikari加add-max-connection-error-message: true让超时异常带出当时的活跃连接数、空闲连接数与等待线程数。若等待线程数远大于maximumPoolSize并发预算问题成立与锁无关。第二步用 JFR 排除 pin。压测期间录制jdk.VirtualThreadPinned事件事件为 0则排除 pin非 0按事件里的栈去定位synchronized。JDK 21 下还可用-Djdk.tracePinnedThreads打印 pin 栈作为兜底。第三步重算并发预算。用L λWL是目标并发连接数λ是目标 QPSW是单请求持有连接的时长。原来 200 个平台线程天然把L卡在 200 以内虚拟线程放开后L只受W和λ约束。可复用的判读规则给分支不给数字/lock路径 pin 事件为 0、/sync明显非 0 → pin 结论成立改锁。两条路径 pin 事件都为 0连接池超时照旧 → 结论是池容量与 pin 无关。关虚拟线程能扛住的 QPS开之后更快超时 → 并发预算没有重新分配。替代方案与取舍方案选择条件代价边界什么情况下不该用保持 200 平台线程只调池与超时请求内无长阻塞风险最低低改配置加回归请求阻塞超过数秒时线程天然限流会推高尾延迟开虚拟线程并按L λW重算池压测能给出WDB 侧能承受更高连接数中需压测与 DB 容量评估连接数受授权或实例规格限制、下游已有自身瓶颈时不该用缩短连接持有时间查询下推、缓存、拆Transactional边界能从业务上降低W中高涉及事务边界重构强一致逐条读写、无法合并的写入不适用入口限流或队列削峰保护下游牺牲部分请求及时性低中引入网关或 MQ交互式接口不能排队三、关键原理并发预算搬移。200 个平台线程把在途请求卡在 200下游从未被真正压过虚拟线程把线程变成廉价资源在途并发可能涨到数千等待队列按L λW线性放大。虚拟线程解决的是「线程太贵」不是「资源太少」。pin 的边界。JEP 444 明确Thread.sleep、Object.wait、LockSupport.park、阻塞式 socket IO 都不会 pin而持有 monitor 期间阻塞会 pin 住 carrier默认 carrier 数等于 CPU 核数pin 满即吞吐塌陷。JEP 491 处理了synchronized的 pin 问题具体修复到的 JDK 版本需按官方入口核对后再写入变更单。注意 JDBC 等待连接本身不 pin所以「HikariCP 超时」大概率是池问题。监控口径失效。虚拟线程模式下「200/200 跑满」失去意义部分线程计数器也不统计虚拟线程。同一故障会改以「RT 抬高 连接池等待堆积 DB 连接数打满」的形式出现告警消失可能等于指标失效。四、可运行示例环境JDK 21、Spring Boot 3.x、Tomcat、PostgreSQL输入为同一份代码分别以spring.threads.virtual.enabled的true/false各跑一轮。spring:datasource:url:jdbc:postgresql://localhost:5432/demohikari:maximum-pool-size:5connection-timeout:5000add-max-connection-error-message:truethreads:virtual:enabled:trueRestControllerpublicclassDemoController{privatefinalJdbcTemplatejdbc;privatefinalObjectmonitornewObject();privatefinalReentrantLocklocknewReentrantLock();publicDemoController(JdbcTemplatejdbc){this.jdbcjdbc;}GetMapping(/sync)publicStringwithSynchronized(){synchronized(monitor){returnString.valueOf(jdbc.queryForObject(select count(*) from t,Long.class));}}GetMapping(/lock)publicStringwithLock(){lock.lock();try{returnString.valueOf(jdbc.queryForObject(select count(*) from t,Long.class));}finally{lock.unlock();}}}操作步骤java-XX:StartFlightRecordingduration120s,filenameapp.jfr-jarapp.jar# 或快速兜底java-Djdk.tracePinnedThreadsshort-jarapp.jar压测/sync与/lock各 120 秒再执行jcmd pid Thread.print -l观察等待连接的线程。常见失败及其处理把池容量问题当 pin 问题花两天把synchronized全换成Lockpin 事件归零但超时一条没少——原因是池只有 5~10 个连接修复方法是先按L λW重算maximumPoolSize再动锁。五、验证结果与边界预期输出/sync路径的 JFRjdk.VirtualThreadPinned事件非 0 且栈中出现DemoController.withSynchronized/lock路径为 0把maximum-pool-size调大后超时停止。此为依据 JEP 444 行为的推断未验证。实际输出本文未提供任何实测 QPS、耗时或事件计数上述结果需在你的环境中按同样步骤压测取得若两条路径 pin 事件均为 0 而超时依旧应改判为池容量问题。边界连接数受授权或实例规格限制、下游已有自身瓶颈、团队不熟悉阻塞与非阻塞混合调试时不应直接开虚拟线程升级到含 JEP 491 的 JDK 只消除 pin不解决连接池超时别把它当本题答案。另外StructuredTaskScope在 JDK 21 仍是 preview生产代码不要依赖。思考虚拟线程下连接池容量该按L λW重算还是按 DB 实例规格反推上限后取两者较小值监控口径从线程占用率切到连接池等待队列时告警阈值该如何设才能区分正常排队与真实瓶颈参考资料JEP 444: Virtual Threads (JDK 21)JEP 491: Synchronize Virtual Threads without PinningSpring Boot Reference: Servlet Web Applications (Ability to use Virtual Threads)Apache Tomcat 10.1: Executor ConfigurationHikariCP Wiki: About Pool SizingJDK 21 Tools Reference: jcmd
企业数字化 ERP 产品动态
相关推荐
【工程师选酒避坑指南】一桌家常菜,配什么酒 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 8:59:48
DouyinLiveRecorder 直播录制完整指南:主页地址配置一次,实现开播自动监控 DouyinLiveRecorder 直播录制完整指南:主页地址配置一次,实现开播自动监控 【免费下载链接】DouyinLiveRecorder 可循环值守和多人录制的直播录制软件,支持抖音、TikTok、Youtube、快手、虎牙、斗鱼、B站、小红书、pandatv、sooplive、flextv… · 2026/11/5 8:59:48
平均响应两小时,对方却觉得三天没人理:企业微信聊天记录导出的效率分析攻略 月度复盘会上摆了两张纸。
左边是一张统计表,上面写着平均首次响应时长两小时十四分,比上个月快了十一分钟,看起来是件好事。右边是三段从聊天记录里摘出来的原话,最短的一段只有八个字:三天了,没人回我。
… · 2026/11/5 9:05:57
File、IO流 File用于操作文件,IO流用于读写数据1.File文件对象常用方法package com.popo.filedemo;import java.io.File;
import java.io.IOException;public class FileDemo1 {public static void main(String[] args) throws Exception {// 文件对象常用方法File f1 new Fil… · 2026/11/5 9:04:56
Python77:核心语法-面向对象基础-概述 面向过程编程核心思想:把一个需求分解成一系列要执行的步骤,然后按照步骤依次执行这些任务(关注的是流程、步骤)。适用场景:面向过程编程非常直接,适合简单、线性的任务。面向对象编程对象可以理解为现实中… · 2026/11/5 9:03:55
VS2026 打包 C++ 程序生成 EXE,借助 Installer Project 扩展工具 文章目录1. 安装 Microsoft Visual Studio Installer Projects 20222. 添加 Setup Project3. 在 File System 中添加相关文件及项目输出4. Qt 部署5. 生成桌面快捷方式6. 修改桌面快捷方式图标参考资料本文适用情况为:已经通过 visual studio 平台开发并测试好了程序… · 2026/11/5 9:03:55
生产环境 Tomcat 200 线程跑满并报连接池超时:一次虚拟线程阻塞点排查 本文摘要:开启虚拟线程后线程告警消失,HikariCP 连接池超时却更早出现。先用 JFR 事件排除 synchronized 阻塞,再按并发预算重算连接池容量。 一、问题与结论
凌晨告警:http-nio-8080-exec-* 200 个处理线程全部阻塞,… · 2026/11/5 9:02:54
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
多智能体协作系统架构设计与实践优化 1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39
大模型系统性入门实战指南:从原理到部署微调的全链路路线 提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39
鸿蒙文件系统沙箱机制解析与开发实践 1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38