FrankenPHP线程调优核心是监控frankenphp_busy_threads和frankenphp_queue_depth:前者达num_threads上限且后者持续>0说明线程不足;后者偶发1–2正常,持续≥3或反复>10需扩容;务必设置max_wait_time防监控失真;Worker模式下busy_threads恒定,应转而关注worker请求量与失败率。

看 frankenphp_busy_threads 和 frankenphp_queue_depth 这两个指标最直接
FrankenPHP 不像 PHP-FPM 那样靠日志猜负载,它把线程使用状态实时暴露成 Prometheus 指标。关键就两个:
-
frankenphp_busy_threads:当前正在干活的线程数(瞬时值) -
frankenphp_queue_depth:请求排队等线程的长度(非零就说明线程不够用了)
用 curl <a href="https://www.php.cn/link/59f199fc1086cdda3ba78d0a6063e746">https://www.php.cn/link/59f199fc1086cdda3ba78d0a6063e746</a> | grep frankenphp 就能拿到原始数据。压测或高峰时段每 5 秒刷一次,观察趋势:
- 如果
frankenphp_busy_threads长期稳定在num_threads设定值(比如你设了 8,它总显示 8),且frankenphp_queue_depth经常 > 0 → 线程数偏低 - 如果
frankenphp_busy_threads大部分时间 < 50% 的num_threads,同时响应延迟也不高 → 线程可能配多了,白白占内存 -
frankenphp_queue_depth偶尔尖峰冲到 1–2 是正常的;持续 ≥ 3 或反复出现 > 10,基本可以断定线程池扛不住了
max_wait_time 超时会掩盖真实瓶颈,别关它
max_wait_time 默认是禁用的,意味着请求会在队列里一直等,直到有空闲线程。这看起来“不丢请求”,但实际会让监控失真:
- 队列越积越长,
frankenphp_queue_depth持续高位,但你可能误以为只是“临时抖动” - 用户端感知是响应越来越慢,甚至超时(比如浏览器 30s 断连),而 FrankenPHP 日志里却没报错
- 真正的问题(线程不足)被这个“无限等待”拖住了诊断节奏
所以务必显式设置:
立即学习“PHP免费学习笔记(深入)”;
- 生产环境建议从
max_wait_time 10s起步 - 配合监控看
frankenphp_queue_depth在超时前是否频繁打满 - 如果 10s 内大量请求触发超时,再考虑加线程,而不是调大
max_wait_time
别只盯 CPU,num_threads 和 max_threads auto 要分开看
很多人按“CPU 核心数 × 2”设完 num_threads 就不管了,但 FrankenPHP 的弹性机制藏在 max_threads:
-
num_threads是启动时预分配的固定线程数,决定冷启动性能 -
max_threads auto允许运行时动态扩容,但扩容有代价:每个新线程都要加载 PHP 扩展、初始化 Zend 引擎,不是无成本的
容易踩的坑:
- 高并发突增时,
max_threads auto可能来不及拉起足够线程,导致短时排队飙升 - 如果你应用本身有较多 I/O 等待(比如 Redis 查询、API 调用),单个线程实际 CPU 利用率不高,这时靠增加
num_threads比依赖max_threads更稳 -
max_threads设太大会让内存占用不可控,尤其 Laravel 这类框架单进程常驻内存轻松过 50MB
建议做法:
- 初始部署先固定
max_threads(比如和num_threads相同),跑 24 小时看指标 - 确认
frankenphp_busy_threads峰值没长期顶到上限,再放开max_threads auto - 同时观察系统
top里的 RES 内存,避免线程数膨胀后 OOM
Worker 模式下 frankenphp_busy_threads 的含义变了,别套用经典模式逻辑
经典模式(即零改动 Laravel)里,每个线程 = 一个同步 PHP 请求处理单元,busy_threads 直观反映并发请求数。
但启用 Worker 模式后:
- 一个 PHP worker 进程会长期持有 1 个线程,持续轮询请求
- 即使 worker 当前没处理 HTTP 请求,只要它在运行中,就算作
busy_threads - 所以你会看到
frankenphp_busy_threads≈worker num,几乎恒定,不再反映瞬时负载
这时候要看的是:
-
frankenphp_worker_requests_total(每个 worker 处理过的请求数) -
frankenphp_worker_failures_total(失败次数,尤其配合max_consecutive_failures) - 日志里是否频繁出现
worker <name> restarted after N failures</name>
换句话说:Worker 模式下,线程数指标退居二线,worker 生命周期和错误率才是健康度核心信号。
线程配置不是设完就一劳永逸的事——它得跟着你的实际流量形状、I/O 特征和错误容忍度一起调。最危险的不是配少,而是配多却不自知:内存悄悄吃紧,GC 压力上升,某次 deploy 后延迟毛刺变多,却还在查代码逻辑。



















