mirror of
https://github.com/eunomia-bpf/bpf-developer-tutorial.git
synced 2026-10-31 04:36:26 +08:00
add new topics (#132)
* add goroutine text * update * fix funclatency * update doc * update about nginx * update nginx * u[date co * fix compile
This commit is contained in:
149
src/39-nginx/README.md
Normal file
149
src/39-nginx/README.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# 使用 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](https://github.com/eunomia-bpf/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 函数执行时间的脚本:
|
||||
|
||||
```bt
|
||||
#!/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 请求:
|
||||
|
||||
```bt
|
||||
# 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` 函数的延迟:
|
||||
|
||||
```console
|
||||
# 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 仓库](https://github.com/eunomia-bpf/bpf-developer-tutorial/blob/main/src/33-funclatency) 中找到 `funclatency` 工具。
|
||||
|
||||
## 结论
|
||||
|
||||
通过 eBPF 跟踪 Nginx 请求可以为您的 Web 服务器提供宝贵的性能洞察,使您能够监控、分析和优化其操作。使用 `bpftrace` 和 `funclatency`
|
||||
|
||||
等工具,您可以测量函数执行时间、识别瓶颈,并根据数据做出决策来改进 Nginx 部署。
|
||||
|
||||
如果您有兴趣了解更多关于 eBPF 的知识,包括更多高级示例和教程,请访问我们的 [https://github.com/eunomia-bpf/bpf-developer-tutorial](https://github.com/eunomia-bpf/bpf-developer-tutorial) 或查看我们的网站 [https://eunomia.dev/tutorials/](https://eunomia.dev/tutorials/)。
|
||||
Reference in New Issue
Block a user