num_threads应设为CPU核心数的1–2倍,但需依负载类型和硬件调整:4核推荐6、8核起始设8、1核2G必须设1;max_threads不可设auto,应设为num_threads+4等合理上限,并配合容器内存限制(如8线程需至少512MB)与OPcache调优。

num_threads 应该设为 CPU 核心数的 1–2 倍
FrankenPHP 默认用 num_threads auto,实际会设成 CPU 核心数 × 2;但这只是安全起点,不是最优解。线程是 OS 级线程,每个活跃线程理想情况下应独占一个逻辑核心——超配会导致上下文切换开销反升,尤其在 1 核或 2 核小机器上更明显。
- 4 核服务器:推荐
num_threads 6(非必须拉满 8),留出调度余量 - 8 核服务器:从
num_threads 8起步,压测时观察frankenphp_threads_busy / frankenphp_threads_total比值 - 1 核 2G 小内存机:必须设
num_threads 1,设 2 就可能因调度争抢和内存压力导致响应抖动
max_threads 不要设 auto,得给紧急扩容划上限
max_threads 是运行时可动态新增的额外线程上限,不包含 num_threads 的初始线程。设成 auto 看似灵活,实则危险:突发流量下线程无限创建,内存暴涨、OOM Killer 直接杀进程,连日志都来不及写。
- 若
num_threads 6,建议max_threads 10(即最多再加 4 个) - 扩容阈值本质是“允许多少请求排队等待线程”,不是并发能力指标
- 配合
max_wait_time 5s使用:当队列里请求等线程超 5 秒,直接返回 503,避免雪崩
别只看 CPU%,重点盯 frankenphp_queue_depth 和 busy 率
CPU 利用率低 ≠ 系统健康。FrankenPHP 高延迟但 CPU 不高,90% 是线程池被 I/O 卡住(如慢 SQL、未设 timeout 的 cURL),新请求全堵在队列里。
- 访问
/metrics(需 Caddy 启用prometheus指令),查frankenphp_queue_depth:持续 > 0 就说明线程不够用 - 同时看
frankenphp_threads_busy和frankenphp_threads_total:比值长期 > 0.8,优先调大num_threads,而不是加 CPU - 用
htop -p $(pgrep -f frankenphp)看线程状态:大量S(sleep)+ 高queue_depth= 外部依赖阻塞,不是线程数问题
容器部署时,线程数和内存限制必须联动算
容器内存限制(-m 1g)不是可选项,而是硬约束。FrankenPHP 每个线程常驻内存约 25–40MB(含 OPcache、框架类加载),8 个线程就吃掉 320MB 起步。只调 memory_limit=256M 没用,OOM Killer 会直接干掉整个容器。
立即学习“PHP免费学习笔记(深入)”;
- 设
num_threads 8→ 容器内存至少-m 512M,推荐-m 1g - 设
num_threads 16(16 核场景)→ 至少-m 2g,否则压测中途必被 kill - OPcache 内存(
opcache.memory_consumption)也要同步收紧:线程多时设128,别用默认256,避免挤占总内存
-m 的 FrankenPHP 容器,扛不住任何真实流量。



















