eBPF通过uprobe/uretprobe精准捕获Nginx真实请求处理耗时,以ngx_http_process_request为起点、ngx_http_finalize_request为终点,排除网络与IO干扰,纳秒级测量纯应用逻辑耗时。

直接在内核层捕获 Nginx 真实请求处理耗时,eBPF 是目前最可靠的方式——它绕过日志采样、不依赖代理、不修改代码,能精确到纳秒级,并覆盖从连接建立到响应发出的完整路径。
关键函数对:用 uprobe + uretprobe 定位真实起点与终点
Nginx 的请求生命周期不是黑盒,核心处理逻辑有明确的入口和出口函数:
- ngx_http_process_request:HTTP 请求解析完成、正式进入业务逻辑的起始点(非 accept 或 read 阶段)
- ngx_http_finalize_request:响应已构造完毕、准备写入 socket 的最终节点(含 header/body 发送前状态)
- 两者之间的时间差,就是纯“应用层请求处理耗时”,排除了网络收发、SSL 握手、磁盘读取等干扰项
避免常见偏差:区分 request_time 与真实处理时间
Nginx 自带的 $request_time 是从接收第一个字节开始计时,到发送完最后一个字节结束,包含:
- TCP 连接建立延迟(SYN/SYN-ACK 往返)
- SSL/TLS 握手耗时(可能受 OCSP Stapling、证书加载影响)
- 客户端慢速上传(如大文件 POST)
- 后端响应等待(
$upstream_response_time)
而 eBPF 跟踪上述两个函数,只测量 Nginx worker 在内存中解析、路由、变量展开、执行 rewrite/if、调用 upstream 模块等动作本身所花时间,更贴近“逻辑处理性能”本质。
实操脚本:bpftrace 快速上线监控
保存为 nginx_req_latency.bt,运行 sudo bpftrace nginx_req_latency.bt:
#!/usr/sbin/bpftrace
// 记录请求处理开始
uprobe:/usr/sbin/nginx:ngx_http_process_request {
@start[tid] = nsecs;
}
// 请求处理结束,计算并输出 >200ms 的慢请求
uretprobe:/usr/sbin/nginx:ngx_http_finalize_request /@start[tid]/ {
$elapsed = nsecs - @start[tid];
if ($elapsed > 200000000) {
printf("SLOW REQ %dms (tid:%d)\n", $elapsed / 1000000, tid);
}
delete(@start[tid]);
}
进阶定位:关联上下文缩小根因范围
单看耗时还不够,需结合上下文判断为何慢:
- 在
ngx_http_process_request入口处,用arg1(ngx_http_request_t *)提取 URI、Host、请求方法,打上标签 - 在
uretprobe中检查retval,若为负值(如-4表示 NGX_ERROR),说明中途异常退出 - 叠加跟踪
ngx_http_upstream_send_request和ngx_http_upstream_process_header,可分离出是本地逻辑慢,还是卡在等待上游


















