Composer请求延迟无法被Prometheus原生采集,必须通过eBPF在内核态钩住PHP进程的socket系统调用链,否则仅见HTTP 200等无意义状态码;因其HTTPS请求由cURL或stream扩展直接发起,不经过Web服务器层,且TLS握手耗时占比超40%,需结合pid、cgroup_id和调用栈实现进程级精准追踪。

Composer 镜像请求延迟无法被 Prometheus 原生采集,必须靠 eBPF 在内核态钩住 PHP 进程的 socket 系统调用链,否则你看到的只是“HTTP 200”这种无意义状态码。
为什么 Composer 请求延迟不能只看 HTTP 指标
Composer 的 composer install 或 composer update 实际会发起大量 HTTPS 请求(如 packagist.org、私有 repo),但这些请求由 PHP 内置的 cURL 或 stream 扩展发起,不走标准 HTTP 代理,传统 Nginx/Apache 日志或 sidecar 拦截完全不可见。Prometheus 的 http_request_duration_seconds 只能覆盖 Web 服务层,对 CLI 场景无效。
- PHP 进程直接调用
connect、sendto、recvfrom,eBPF 必须在 syscall 层捕获 - Composer 使用的 TLS 握手耗时(尤其是证书验证、OCSP stapling)占总延迟 40%+,仅靠应用层埋点无法分离
- 同一台宿主机上多个 PHP 进程并发请求,需通过
pid+cgroup_id绑定到具体 Composer 执行实例
如何用 eBPF 钩住 Composer 的真实请求链路
核心是复用 BCC 工具链中的 tcpconnect 和 tcplife 逻辑,但要额外注入 PHP 进程上下文。以下为最小可行配置:
- 使用
uprobe钩住 PHP 的php_stream_context_set_option,提取 URL host 和 port,避免依赖 DNS 解析结果 - 用
kprobe捕获tcp_v4_connect入口,记录pid和bpf_ktime_get_ns()起始时间 - 用
kretprobe捕获tcp_v4_connect返回值,计算 delta 并写入BPF_HISTOGRAM,桶按微秒 log2 划分(bpf_log2l(delta / 1000)) - 关键:通过
bpf_get_current_cgroup_id()获取 cgroupv2 path,再映射到容器名或 Composer project root(如/sys/fs/cgroup/pod-xxx/.../php-composer-abc)
指标暴露给 Prometheus 的关键适配点
ebpf_exporter 本身不支持 PHP 进程级标签注入,必须自定义 exporter 或改写其 examples/http-latency.yaml:
- 在
metricssection 中添加labels: [cgroup_name, php_version, composer_command],其中cgroup_name来自 eBPF map 查表 - 将原始延迟直方图转为 Prometheus 兼容格式:
composer_http_request_duration_seconds_bucket{le="0.01",cgroup_name="my-app"} 127 - 注意:
ebpf_exporter默认只读取BPF_HISTOGRAM类型 map,若用BPF_HASH存 per-request detail,需额外开发用户态聚合逻辑 - 避免在 eBPF 程序中做字符串拼接(如拼接 URL),会触发 verifier 拒绝;URL 应由用户态从
perf_output或ringbuf中解析
容易被忽略的兼容性陷阱
不是所有 PHP 版本和运行模式都适用同一套 eBPF 钩子:
- PHP-FPM 模式下,
pid复用频繁,必须结合tid(线程 ID)或task_struct->comm匹配composer字符串 - PHP 8.1+ 启用 JIT 后,
uprobe可能因函数内联失效,建议降级到tracepoint:syscalls:sys_enter_connect保底 - Alpine Linux 容器默认用 musl libc,
php_stream_context_set_option符号不可见,需改用ssl_write/ssl_readuprobe - 如果 Composer 使用
--no-plugins,部分网络行为会绕过 stream wrapper,此时必须监听openat对/etc/hosts或 CA bundle 的读取来辅助定位
真正难的不是写 eBPF 代码,而是让每一条 Composer 请求都能稳定带上可追溯的 identity 标签——cgroup、PID、PHP 调用栈三者缺一不可,漏掉任何一个,指标就变成“平均延迟”,失去根因分析价值。


















