最直接信号是frankenphp_queue_depth持续>0,表明请求排队、线程池饱和;需结合threads_busy/total比值>0.8、大量线程处于s状态及99%延迟阶梯式上升交叉验证。

看 frankenphp_queue_depth 是否持续大于 0
这是最直接的信号。FrankenPHP 的请求不是“来了就处理”,而是先入队,再由空闲线程消费。如果 frankenphp_queue_depth 在 /metrics 端点里长期 > 0(比如连续 10 秒 ≥ 2),说明新请求进不来,线程池已无可用线程承接。
注意:这个指标和 CPU 使用率无关。即使 top 显示 CPU 只有 20%,只要队列深度不归零,就是满负荷调度状态。
- 用
curl http://localhost/metrics | grep frankenphp_queue_depth实时观察 - 结合
frankenphp_threads_busy和frankenphp_threads_total算比值:若busy/total > 0.8持续 30 秒以上,基本可判定线程池饱和 - 别依赖
ps aux | grep frankenphp-worker数进程数——它只反映 worker 数量,不反映线程实际负载
查日志里是否高频出现 Worker #X restarted after max_requests
这说明 worker 进程在达到 max_requests 限制后被强制回收,紧接着又拉起新进程。高频重启(如每分钟 ≥ 3 次)意味着单个 worker 承载请求过多、生命周期过短,无法稳定维持服务,属于隐性满负荷。
- 检查
max_requests值是否设得太小(例如50),而实际内存峰值远未触顶 - 对比
memory_get_peak_usage(true)日志:若峰值长期稳定在 30MB,却设了max_requests 100,那重启纯属冗余,应调高 - 若重启伴随
Allowed memory size exhausted,才是真内存不足;否则大概率是配置与负载不匹配
用 htop -p $(pgrep -f frankenphp) 看线程状态分布
top 只给平均 CPU,htop -p 能看到每个线程的真实状态。满负荷时典型特征是:大量线程处于 S(sleep)而非 R(running)——它们不是在等 CPU,是在等 I/O、数据库连接、cURL 响应或锁释放。
- 执行命令后按
H切换线程视图,关注STATE列 - 若 > 60% 的 PHP 线程显示
S,且frankenphp_queue_depth > 0,基本锁定为下游阻塞(如 MySQL 连接池耗尽、Redis 超时、文件读写锁) - 此时加核无效,要查
netstat -an | grep :3306 | wc -l等连接数,或用strace -p [pid]抓某个 S 状态线程在等什么系统调用
观察 99% Latency 是否随并发阶梯式上升
真正满负荷的副作用不是报错,而是长尾延迟恶化。用 wrk -t4 -c200 -d30s http://localhost/health 压测,如果 Latency (99%) 从 120ms 跳到 850ms,而 Requests/sec 下降不到 10%,说明请求在队列里排队等待,线程池已无冗余处理能力。
- 不要只看平均延迟——它会被大量快请求拉低,掩盖排队事实
- 对比压测前后
frankenphp_threads_busy曲线:若从 0.3 爬升到 0.95 且卡住,就是临界点 - 此时再增并发,
frankenphp_queue_depth会指数级增长,而非线性,这就是过载拐点
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











