java性能监控关键在于精准计时与有效使用:用nanotime()测单次操作耗时,currenttimemillis()对齐分布式链路;打点需贴近业务边界,日志须含traceid、接口名、耗时、状态等结构化字段,并通过采样、异步、熔断及micrometer+prometheus实现可落地监控。

Java 中记录请求耗时与性能监控,关键不是“记不记”,而是“怎么记准、怎么用好”。核心是时间采集要准、上下文要全、上报要稳、分析要可落地。
选对时间源:nanoTime() 用于精度,currentTimeMillis() 用于稳定性
短时操作(如单次序列化、方法执行)优先用 System.nanoTime():它不受系统时钟回拨影响,纳秒级分辨率,适合测量毫秒甚至微秒级耗时。记得转成毫秒或微秒再打日志,更易读。
HTTP 请求整体耗时这类跨组件、需对齐链路时间的场景,用 System.currentTimeMillis() 更稳妥——虽然精度低一点,但各服务间时间戳语义一致,便于和 traceId 对齐、做分布式聚合。
不要混用两者做差值;同一计时过程必须用同一个 API。
打点位置决定数据价值:贴近真实业务边界
耗时失真,八成是因为打点位置漂了:
- HTTP 接口:起点放在 Controller 方法内、参数校验通过后;终点放在 return 前或 finally 块中(确保异常路径也覆盖)
- DB 操作:起点在 PreparedStatement.execute() 调用前,终点在 execute() 返回后,排除连接获取、结果集映射等干扰
- RPC 或序列化:起点在 writeObject() 前,终点在 readObject() 成功返回对象后;失败时别计入正常耗时,要单独记录异常类型
避免在 DispatcherServlet 入口或 Filter 最外层打点——那测的是框架开销,不是你的业务。
结构化日志 + 上下文字段,让日志真正可查可用
光写“耗时 128ms”没意义。每条耗时日志至少应含:
- traceId:全链路唯一标识,对接 SkyWalking / Zipkin 等追踪系统
- interfaceName 或 uri:明确是哪个接口或方法
- costTime(单位统一为 ms)、startTime(毫秒时间戳)
- status(success / failed)、exception(异常类名,如 IOException、ClassNotFoundException)
- serverIp、clientIp(如有)
用 SLF4J 的 MDC 放入 traceId 和用户 ID,再配合 Logback 的 pattern 自动注入,无需每处手动拼字符串。
从日志走向监控:采样、异步、熔断、可视化
高频接口全量打点会拖慢系统。生产建议:
- 对 P95/P99 超阈值(如 >500ms)或失败请求强制记录,其余按比例采样(如 1%)
- 日志写入走异步 Appender(如 Logback AsyncAppender),避免阻塞业务线程
- 打点模块自身延迟超 50ms 或失败率过高时,自动熔断,防止雪崩
- 把耗时指标接入 Micrometer + Prometheus,暴露 /actuator/metrics,用 Grafana 看 P90/P99 曲线和突增告警
Apache 层 %D 只能看网络+响应头耗时;要获得 Java 真实处理时间,必须由应用自己算好,通过 X-Process-Time 响应头传给 Apache 日志捕获。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











