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

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

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

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

要点速览
  • duration=30s 决定这次录制何时自动结束,filename 决定结果落到哪个文件。
  • threshold 只过滤事件,不代表整个 HTTP 请求耗时;应用路由需要自定义 JFR 事件或结合其他证据。
  • 先看事件总量,再看 jdk.SocketRead、jdk.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推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    595次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    635次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    668次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    634次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    452次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码