通过curl http://localhost:9100/metrics | grep frankenphp_busy_threads获取实时值,该指标仅在启用php_server或worker模式、显式配置workers.count且Caddyfile中启用{ prometheus :9100 }时有效,需结合frankenphp_total_threads比值(>0.8且queue_depth>0表线程池饱和)判断真实负载。

怎么查 frankenphp_busy_threads 实时值
这个指标不是 FrankenPHP 自己打印的日志,而是通过 Caddy 暴露的 Prometheus metrics 端点返回的。你得先确认 Caddyfile 里启用了 prometheus 指令,比如:
{<br> prometheus :9100<br>}
然后用 curl 直接拉取:
curl http://localhost:9100/metrics | grep frankenphp_busy_threads
输出类似 frankenphp_busy_threads{server="default"} 3,那个 3 就是当前正忙的线程数。注意:它只在启用 php_server 或 worker 模式时才有效,纯静态 reverse_proxy 不会触发该指标。
为什么不能只看 top 或 ps 里的线程数
top -H -p $(pgrep -f frankenphp) 看到的是 OS 级线程(包括 Go runtime 管理线程、网络轮询线程等),而 frankenphp_busy_threads 特指“正在执行 PHP 字节码”的线程——也就是真正干活的那批。两者数量经常不一致:
立即学习“PHP免费学习笔记(深入)”;
- OS 层可能有 20+ 个线程,但
frankenphp_busy_threads长期为 0 → PHP 层空闲,瓶颈在路由或静态文件处理 -
frankenphp_busy_threads满了(比如等于frankenphp_total_threads),但top里 CPU 使用率只有 30% → 线程卡在 I/O 上(如 DB 查询、cURL 等待响应),不是 CPU 不够 - 某些线程在
S(sleep)状态,但frankenphp_busy_threads仍计数 → 它把等待 PHP 执行上下文的线程也算作“busy”,因为请求已入队、资源已被占用
监控时容易忽略的三个条件
这个指标要能准确反映负载,得满足以下前提,缺一不可:
- Caddy 的
php_server必须启用,且路径匹配实际 PHP 请求(比如/api/*),否则指标始终为 0 - FrankenPHP 启动时必须带
workers.count或num_threads显式配置,设成auto可能导致指标上报延迟或归零 - 别用
ab或简单curl循环测——单连接压测会让frankenphp_busy_threads在 0 和 1 之间跳,看不出池子是否饱和;要用wrk -c100 -t4这类多连接工具,才能让指标稳定在合理区间
比值比绝对值更有用:盯住 frankenphp_busy_threads / frankenphp_total_threads
单独看 frankenphp_busy_threads = 5 没意义,得结合分母判断压力程度:
- 比值持续 > 0.8,且
frankenphp_queue_depth> 0 → 线程池真不够,请求开始排队,响应延迟上升 - 比值长期 ≈ 0.3,但 QPS 卡在某个值上不去 → 可能是下游 DB/Redis 响应慢,线程都在等,不是线程数问题
- 比值忽高忽低(比如 0→6→0→6),周期约 30 秒 → 检查是否开了
max_requests,Worker 正在轮换重启,属于正常抖动
这个比值才是调优 workers.count 或 num_threads 的核心依据,而不是盯着某次压测的峰值数字硬凑。



















