当前位置:首页 > 文章列表 > 文章 > java教程 > Java JFR 如何只录制一次慢请求窗口

Java JFR 如何只录制一次慢请求窗口

来源:17golang原创 2026-09-07 18:31:19 0浏览 收藏

Java 服务出现偶发慢请求时,不必先把 JFR 常驻成一份巨大的连续录制。更稳妥的做法是:从 default.jfc 复制一份临时配置,给关心的阻塞事件设置阈值,再用 jcmd JFR.start 只录制 30 秒,最后用 jfr summaryjfr print 读取同一个 .jfr 文件。这样得到的是一次有边界的现场,既能保留调用栈,又不会把所有短事件都混进结果。

要点速览
  • duration=30s 决定这次录制何时自动结束,filename 决定结果落到哪个文件。
  • threshold 只过滤事件,不代表整个 HTTP 请求耗时;应用路由需要自定义 JFR 事件或结合其他证据。
  • 先看事件总量,再看 jdk.SocketReadjdk.JavaMonitorWait 和调用栈,才能判断慢点落在哪个边界。

先把一次录制的边界定下来

这类排查至少有四个边界:业务请求事件、事件阈值、录制窗口和结果文件。JFR 的 duration 事件只有达到 threshold 才会被记录;窗口结束后,数据写入一个可复查的 slow-window.jfr。如果只观察网络或锁,可以直接使用 JFR 内置事件;如果必须按路由定位,就在服务代码里增加一个自定义请求事件,让它的字段包含路由、状态码和耗时。

Java JFR 慢请求排查中业务请求事件、threshold、30 秒录制与 slow-window.jfr 的静态边界关系
图1:把业务请求事件、阈值、一次录制窗口和结果文件放在同一组边界里,避免把事件阈值误认为接口总耗时。

从 default.jfc 生成只保留慢事件的配置

不要直接修改 JDK 自带的配置文件。用 jfr configure 从默认配置生成一份项目专用文件,只调整本次要看的 duration 事件。例如下面把网络读写和锁等待都设为 20 毫秒;短于这个值的事件不会进入这次录制。

# 从默认配置派生临时配置,不改动 JDK 自带文件
jfr configure --input "$JAVA_HOME/lib/jfr/default.jfc" \
  --output /opt/jfr/slow-request.jfc \
  jdk.SocketRead#threshold=20ms \
  jdk.SocketWrite#threshold=20ms \
  jdk.JavaMonitorWait#threshold=20ms

如果运行环境的 JDK 没有这个路径,先用 jfr configure --help 和实际的 JAVA_HOME 确认配置位置。阈值越低,捕获的短事件越多;阈值越高,文件更干净,但可能漏掉由大量短等待叠加形成的请求问题。

用 jcmd 启动一次性慢请求窗口

找到目标 JVM 的 PID 后,显式指定名称、配置、时长和文件名。duration=30s 到期后自动结束,适合让问题复现一次;不要省略 duration,否则默认值可能让录制一直运行。

# 先确认目标进程,再启动唯一一个 30 秒录制
jcmd  VM.version
jcmd  JFR.start name=slow-window \
  settings=/opt/jfr/slow-request.jfc \
  duration=30s \
  filename=/tmp/slow-window.jfr

# 复现慢请求期间查看录制状态
jcmd  JFR.check name=slow-window

需要按路由和状态码判断时,可以在请求入口包住一个应用事件。事件类上的 @Threshold 是默认过滤线,commit() 会结束本次事件的计时;下面的字段会随事件写入 JFR。

import jdk.jfr.Category;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.Threshold;

@Name("demo.HttpRequest")
@Label("HTTP Request")
@Category({"Demo", "HTTP"})
@Threshold("200 ms")
final class HttpRequestEvent extends Event {
    @Label("Route") String route;
    @Label("Status") int status;
}

// 在请求入口开始,在响应状态确定后提交事件
HttpRequestEvent event = new HttpRequestEvent();
event.route = "/orders/{id}";
event.begin();
try {
    // 这里调用实际业务处理,并在结束前写入状态码
    event.status = 200;
} finally {
    event.commit();
}

这段自定义事件只说明“哪个请求超过 200 毫秒”,不替代网络、锁和 CPU 事件。真实项目中应把 route 做成低基数模板,避免把用户参数直接写进事件字段。

用 jfr summary 与 print 读取同一个文件

录制结束后先做摘要,再做定向读取。摘要用来确认文件确实包含目标事件,定向输出用来抓 duration、线程和调用栈。

# 先看事件数量和录制基本信息
jfr summary /tmp/slow-window.jfr

# 再读取可能造成慢请求的阻塞事件与调用栈
jfr print --events jdk.SocketRead,jdk.SocketWrite,jdk.JavaMonitorWait \
  --stack-depth 20 /tmp/slow-window.jfr

# 如果写入了应用级事件,再单独过滤它
jfr print --events demo.HttpRequest /tmp/slow-window.jfr
Java JFR 结果读取中 slow-window.jfr 连接到 jfr summary、jfr print、SocketRead、JavaMonitorWait 与调用栈
图2:从 slow-window.jfr 分出摘要、事件过滤和调用栈三条读取关系,先确认数量再解释慢点。

判断时不要把一个 jdk.SocketRead 直接当成接口总耗时:它说明线程在 socket 读取上等待过;jdk.JavaMonitorWait 更接近锁或条件等待;自定义 demo.HttpRequest 才能给出路由级的请求窗口。三者的线程、时间范围和调用栈能够相互印证时,结论才足够可靠。

常见问题

为什么设置了 threshold 仍然看不到某个慢请求?

threshold 只作用于对应事件类型,且事件必须真的被启用。路由级耗时如果没有自定义事件,单看 SocketRead 不能覆盖全部业务执行时间。

duration 到期后还需要执行 JFR.stop 吗?

不需要。duration 到期会结束这次录制并写入 filename;只有提前结束或需要立即落盘时,才用带 name 的 JFR.stop

为什么不直接使用 profile?

profile 适合短时间获取更多信息,但仍可能产生更多事件。先从 default 配置派生并提高目标事件阈值,更适合一次只看慢请求窗口的排查。

最终检查只看三件事:录制是否只有一个明确的 name,文件是否按预期生成,以及结果中是否同时出现事件类型、duration 和可解释的调用栈。满足这三点,就可以把 JFR 现场交给后续的代码或链路排查。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go GOPROXY 怎么为内网模块配置回源策略Go GOPROXY 怎么为内网模块配置回源策略
上一篇
Go GOPROXY 怎么为内网模块配置回源策略
Go HTTP 重定向为什么改变了 POST 请求方法
下一篇
Go HTTP 重定向为什么改变了 POST 请求方法
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    173次使用
  • C-Eval中文评测基准:大语言模型多学科能力评估指南
    C-Eval
    深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
    103次使用
  • AI Prompt Library:免费AI提示词库,助力ChatGPT高效创作与营销
    AI Prompt Library
    探索AI Prompt Library免费资源库,涵盖营销、写作及多场景AI提示词。兼容ChatGPT、Claude等工具,一键复制优化输出,提升工作效率。
    31次使用
  • LangGPT提示词框架:结构化Prompt设计方法与开源工具指南
    LangGPT
    LangGPT是一种受编程语言启发的结构化提示词设计工具,提供双层框架、模块化模板及变量功能,帮助用户高效编写高质量Prompt。该项目已在GitHub免费开源,适用于内容创作、编程辅助等多场景。
    40次使用
  • ClickPrompt:AI提示词生成与优化工具,支持Stable Diffusion、ChatGPT及代码辅助
    ClickPrompt
    ClickPrompt是一款专为AI提示词编写者设计的开源在线工具,支持Stable Diffusion绘图、ChatGPT对话及GitHub Copilot代码辅助。提供Prompt自动生成、一键运行、社区分享及可视化优化功能,帮助用户高效获取精准AI输出。
    76次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码