apache不直接测量java应用内部耗时,需java通过x-process-time响应头传递并用%{x-process-time}o记录;%d仅记录apache层面微秒级请求头收发耗时,不含后端处理时间。

Apache 本身不直接测量 Java 或其他后端应用的内部处理时间,但可以通过 mod_log_config 精确记录 Apache 层面的请求生命周期耗时;网络往返时延(如客户端到 Apache 的 RTT)则需结合响应头或代理层(如 HAProxy)间接推断。关键在于区分“Apache 接收-响应头发出”和“真实端到端延迟”。
用 %D 记录 Apache 层面微秒级处理耗时
%D 是最常用、开销最小的耗时字段,表示从 Apache 接收到请求第一个字节,到发送完响应头(headers sent)所经过的微秒数。它不包含响应体传输时间,也不含后端 Java 应用执行逻辑的时间。
- 确认
mod_log_config已启用:运行httpd -M | grep log_config,看到log_config_module (shared)即表示已加载 - 在
httpd.conf或虚拟主机配置中定义日志格式:LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" timed_combined - 启用该格式:
CustomLog logs/access_log timed_combined - 日志示例末尾数字为微秒值:
192.168.1.50 - - [28/Apr/2026:12:15:22 +0800] "GET /api/data HTTP/1.1" 200 312 "-" "curl/8.5.0" 142893→ 约 143 ms
获取 Java 应用真实处理耗时(需应用配合)
若要记录 Spring Boot、Tomcat 等 Java 应用内部执行耗时,必须由应用自身计算并写入响应头,Apache 再通过 %{X-Process-Time}o 捕获。
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- Java 端(如 Filter 或 Interceptor 中)设置响应头:
response.setHeader("X-Process-Time", String.valueOf(System.nanoTime() - startTimeNanos) / 1_000_000);(转为毫秒) - Apache 配置中扩展日志格式:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D %{X-Process-Time}o" java_timing - 注意:
%{X-Process-Time}o中的o表示 output(响应头),不是i(请求头);若应用未设置该头,日志中对应位置显示为-
估算网络往返时延(RTT)与端到端延迟
Apache 原生不记录客户端网络延迟,但可通过组合字段和外部工具逼近:
-
%D+ 客户端发起时间(需客户端埋点)→ 可反推 RTT:假设客户端记录请求发出时刻t1、收到响应头时刻t2,则RTT ≈ (t2 − t1) − %D - 若前端使用 JavaScript,可借助
performance.timing获取responseStart − requestStart,再减去 Apache 日志中的%D(需时间同步) - 更可靠的方式是前置负载均衡器(如 HAProxy):其
%Tr字段表示“从 HAProxy 发完请求到收第一个响应字节”的耗时,即Apache 处理时间 + 网络传输时间;对比 HAProxy 的%Tr和 Apache 的%D,差值可近似为网络链路延迟
补充:避免常见误用
几个容易踩坑的点:
-
%T是整秒截断值(非四舍五入),精度太低,不适合性能分析 -
%D实际精度受系统时钟影响,高并发下可能有微小偏差;对极致精准计时,Java 端应优先用System.nanoTime() - 日志字段序号随
LogFormat变动,用awk统计前务必先用head -1 access.log | awk '{print NF; print $0}'确认%D所在列号 - 不要混淆
%D(Apache 层)和 Nginx 的$request_time(Nginx 自有变量,Apache 不支持)










