使用 eBPF 跟踪 Nginx 请求
Nginx 是世界上最流行的 Web 服务器和反向代理之一,以其高性能、稳定性和低资源消耗而闻名。它广泛用于提供静态内容、负载均衡以及作为动态应用的反向代理。为了保持其性能优势,监控和优化 Nginx 的运行尤为重要,尤其是在处理大量请求时。利用 eBPF(扩展的伯克利包过滤器),可以深入了解 Nginx 的性能表现,识别瓶颈并进行优化,而无需修改源代码或重启服务。
引言
Nginx 是世界上最流行的 Web 服务器和反向代理之一,以其高性能、稳定性和低资源消耗而闻名。它广泛用于提供静态内容、负载均衡以及作为动态应用的反向代理。为了保持其性能优势,监控和优化 Nginx 的运行尤为重要,尤其是在处理大量请求时。利用 eBPF(扩展的伯克利包过滤器),可以深入了解 Nginx 的性能表现,识别瓶颈并进行优化,而无需修改源代码或重启服务。
eBPF 是一项革命性技术,允许开发人员在 Linux 内核中运行自定义程序。最初设计用于网络数据包过滤,但 eBPF 现已发展为一个多功能工具,广泛应用于跟踪、监控和分析系统行为。通过利用 eBPF,您可以跟踪 Nginx 的关键函数,测量延迟,识别瓶颈,进而优化系统性能。
背景:Nginx 和 eBPF
Nginx
Nginx 采用事件驱动架构,使其在资源占用极少的情况下能够高效处理成千上万的并发连接。这种高效性依赖于其请求处理、响应生成和事件处理等多个性能关键函数。了解这些函数在不同负载下的表现对于优化 Nginx 的使用至关重要。
eBPF
eBPF 程序在 Linux 内核的安全沙盒环境中运行。这些程序可以附加到各种钩子上,如系统调用、跟踪点,甚至可以通过 uprobes(用户级探针)附加到用户空间的函数。这使得 eBPF 成为一个强大的系统可观测性工具,可以收集详细的性能数据并实时执行策略。
eBPF 的一个常见用例是跟踪函数执行时间,以测量延迟。这对于了解 Nginx 中特定函数的执行时间特别有用,有助于诊断性能问题、优化资源使用,并提高 Nginx 部署的整体效率。
Uprobes
Uprobes 是一种用于跟踪用户空间应用程序函数的探针,它通过附加到特定用户空间函数的入口和出口点,可以捕获精确的时间信息。然而,需要注意的是,在内核模式 eBPF 运行时使用 uprobes 可能会带来一定的性能开销。为此,您可以考虑使用基于 LLVM JIT/AOT 的用户模式 eBPF 运行时 bpftime。这种运行时可以在用户空间中运行 eBPF 程序,与内核模式 eBPF 兼容,并有可能降低开销。
Nginx 的性能关键函数
以下是 Nginx 中一些性能关键的函数,可以通过 eBPF 进行监控:
- ngx_http_process_request:负责处理传入的 HTTP 请求。监控此函数有助于跟踪请求处理的开始。
- ngx_http_upstream_send_request:当 Nginx 作为反向代理时,负责向上游服务器发送请求。
- ngx_http_finalize_request:完成 HTTP 请求的处理,包括发送响应。跟踪此函数可以衡量整个请求处理的时间。
- ngx_event_process_posted:处理事件循环中的队列事件。
- ngx_handle_read_event:负责处理来自套接字的读取事件,对监控网络 I/O 性能至关重要。
- ngx_writev_chain:负责将响应发送回客户端,通常与写事件循环结合使用。
使用 bpftrace 跟踪 Nginx 函数
为了监控这些函数,我们可以使用 bpftrace,一种 eBPF 的高级跟踪语言。以下是一个用于跟踪几个关键 Nginx 函数执行时间的脚本:
#!/usr/sbin/bpftrace
// 监控 HTTP 请求处理的开始
uprobe:/usr/sbin/nginx:ngx_http_process_request
{
printf("HTTP 请求处理开始 (tid: %d)\n", tid);
@start[tid] = nsecs;
}
// 监控 HTTP 请求的完成
uretprobe:/usr/sbin/nginx:ngx_http_finalize_request
/@start[tid]/
{
$elapsed = nsecs - @start[tid];
printf("HTTP 请求处理时间: %d ns (tid: %d)\n", $elapsed, tid);
delete(@start[tid]);
}
// 监控向上游服务器发送请求的开始
uprobe:/usr/sbin/nginx:ngx_http_upstream_send_request
{
printf("开始向上游服务器发送请求 (tid: %d)\n", tid);
@upstream_start[tid] = nsecs;
}
// 监控上游请求发送完成
uretprobe:/usr/sbin/nginx:ngx_http_upstream_send_request
/@upstream_start[tid]/
{
$elapsed = nsecs - @upstream_start[tid];
printf("上游请求发送完成时间: %d ns (tid: %d)\n", $elapsed, tid);
delete(@upstream_start[tid]);
}
// 监控事件处理的开始
uprobe:/usr/sbin/nginx:ngx_event_process_posted
{
printf("事件处理开始 (tid: %d)\n", tid);
@event_start[tid] = nsecs;
}
// 监控事件处理的完成
uretprobe:/usr/sbin/nginx:ngx_event_process_posted
/@event_start[tid]/
{
$elapsed = nsecs - @event_start[tid];
printf("事件处理时间: %d ns (tid: %d)\n", $elapsed, tid);
delete(@event_start[tid]);
}运行脚本
要运行上述脚本,先启动 Nginx,然后使用 curl 等工具生成 HTTP 请求:
# bpftrace /home/yunwei37/bpf-developer-tutorial/src/39-nginx/trace.bt
Attaching 4 probes...
事件处理开始 (tid: 1071)
事件处理时间: 166396 ns (tid: 1071)
事件处理开始 (tid: 1071)
事件处理时间: 87998 ns (tid: 1071)
HTTP 请求处理开始 (tid: 1071)
HTTP 请求处理时间: 1083969 ns (tid: 1071)
事件处理开始 (tid: 1071)
事件处理时间: 92597 ns (tid: 1071)该脚本监控了几个 Nginx 函数的开始和结束时间,并打印了每个函数的执行时间。这些数据可以用来分析和优化 Nginx 服务器的性能。
测试 Nginx 的函数延迟
为了更详细地分析函数延迟,您可以使用 funclatency 工具,该工具可以测量 Nginx 函数的延迟分布。以下是如何测试 ngx_http_process_request 函数的延迟:
# sudo ./funclatency /usr/sbin/nginx:ngx_http_process_request
tracing /usr/sbin/nginx:ngx_http_process_request...
tracing func ngx_http_process_request in /usr/sbin/nginx...
Tracing /usr/sbin/nginx:ngx_http_process_request. Hit Ctrl-C to exit
^C
nsec : count distribution
0 -> 1 : 0 | |
524288 -> 1048575 : 16546 |****************************************|
1048576 -> 2097151 : 2296 |***** |
2097152 -> 4194303 : 1264 |*** |
4194304 -> 8388607 : 293 | |
8388608 -> 16777215 : 37 | |
Exiting trace of /usr/sbin/nginx:ngx_http_process_request结果总结
上述结果显示了 ngx_http_process_request 函数的延迟分布。大多数请求在 524,288 至 1,048,575 纳秒内处理完成,少部分请求处理时间更长。这些信息对于识别性能瓶颈和优化 Nginx 请求处理至关重要。
通过使用 funclatency,您可以:
- 识别性能瓶颈:了解哪些函数执行时间最长,并将优化工作重点放在这些函数上。
- 监控系统性能:定期监控函数延迟,确保在高负载下 Nginx 服务器的最佳性能。
- 优化 Nginx 配置:利用延迟测量得出的洞察调整 Nginx 设置或修改应用程序,以提高整体性能。
您可以在 bpf-developer-tutorial 仓库 中找到 funclatency 工具。
结论
通过 eBPF 跟踪 Nginx 请求可以为您的 Web 服务器提供宝贵的性能洞察,使您能够监控、分析和优化其操作。使用 bpftrace 和 funclatency
等工具,您可以测量函数执行时间、识别瓶颈,并根据数据做出决策来改进 Nginx 部署。
如果您有兴趣了解更多关于 eBPF 的知识,包括更多高级示例和教程,请访问我们的 https://github.com/eunomia-bpf/bpf-developer-tutorial 或查看我们的网站 https://eunomia.dev/tutorials/。
继续阅读
返回索引
eBPF 开发实践教程:基于 CO-RE,通过小工具快速上手 eBPF 开发
这是一个基于 CO-RE(一次编译,到处运行)的 eBPF 的开发教程,提供了从入门到进阶的 eBPF 开发实践,包括基本概念、代码实例、实际应用等内容。和 BCC 不同的是,我们使用 libbpf、Cilium、libbpf-rs、eunomia-bpf 等框架进行开发,包含 C、Go、Rust 等语言的示例。
上一篇 / 上一页
using BTF to verify userspace eBPF extensions
Here we will show how to use the type information of userspace application to verify the eBPF program which will access the userspace memory(include valid or invalid data structure memory access, pointer access, etc), an
下一篇 / 下一页
使用 eBPF 跟踪 MySQL 查询
MySQL 是全球最广泛使用的关系型数据库管理系统之一。无论您是在运行小型应用程序还是大型企业系统,了解 MySQL 数据库的性能特征都至关重要。特别是了解 SQL 查询的执行时间以及哪些查询占用了最多的时间,有助于诊断性能问题,并优化数据库以提高效率。
- 最后更新
- 2025年2月10日
- 首次发布
- 2025年2月10日
- 贡献者
- 云微
这个页面有帮助吗?