max_threads 是 frankenphp 运行时可动态创建的额外 php 线程上限,不包含 num_threads 设定的初始常驻线程;num_threads 为启动即分配的固定线程数,max_threads 则是紧急扩容的天花板,例如 num_threads 4、max_threads 12 时,最多可临时新增 8 个线程。

max_threads 是什么,和 num_threads 有什么区别
max_threads 控制 FrankenPHP 运行时能动态创建的**额外 PHP 线程上限**,它不包含初始启动的线程(即 num_threads)。简单说:num_threads 是常驻线程池大小,max_threads 是“紧急扩容”的天花板。
比如你设 num_threads 4、max_threads 12,那服务启动就占 4 个线程;当并发突增、所有线程忙且队列积压时,FrankenPHP 最多再拉起 8 个临时线程(总数不超过 12),撑过峰值后会逐步回收。
注意:若 max_threads 设为 auto,FrankenPHP 会按需无限扩容——这在突发流量下看似安全,但极易引发内存暴涨甚至 OOM,生产环境不建议。
怎么定具体数值:看 CPU 核心数,不是看 QPS
FrankenPHP 的线程是 OS 级线程,每个线程独占一个 CPU 核心调度权。盲目堆高 max_threads 不会提升吞吐,反而因上下文切换和内存争用拖慢整体响应。
- 推荐起点:
max_threads = num_threads × 2(例如num_threads 8→max_threads 16) - 服务器有 8 核?
num_threads设 8~16,max_threads就设 16~24 - 如果应用大量调用外部 HTTP API 或数据库,I/O 等待多,可略放宽(比如
max_threads 32),但必须配合max_wait_time防止请求无限排队 - 纯 CPU 密集型(如图像处理、加密计算)?
max_threads建议 ≤num_threads,避免核间竞争
不设 max_threads 或设太大会出什么问题
常见错误现象:curl 请求卡住、frankenphp_queue_depth 持续上涨、系统 load average 爆表但 CPU idle 很高、dmesg 出现 Out of memory: Kill process。
根本原因不是线程不够,而是线程太多导致:
- 每个 PHP 线程默认吃掉 20–50MB 内存(取决于 opcache 和框架加载量),
max_threads 64在 Laravel 项目里可能直接吃光 2GB+ 内存 - Go runtime 调度器压力陡增,
frankenphp_busy_threads和frankenphp_total_threads差值长期为 0,说明线程全在等 I/O 或锁,不是真忙 - Caddy 的
max_wait_time失效——因为线程创建本身就有延迟,排队请求在等新线程时已超时
验证配置是否合理:盯住三个指标
启用 Caddy metrics 后,用 curl http://localhost:2019/metrics | grep frankenphp 实时观察:
-
frankenphp_busy_threads长期 ≈frankenphp_total_threads?说明线程池常满,该调高num_threads,而不是只加max_threads -
frankenphp_queue_depth> 0 且持续增长?优先检查下游依赖(DB/Redis/API)是否变慢,再考虑小幅上调max_threads -
frankenphp_total_threads频繁在num_threads和max_threads之间震荡?说明扩容/缩容太激进,把max_threads往下调 25% 再观察 24 小时
真正难调的从来不是数字本身,而是分清「是线程不够」还是「是某条 SQL 卡住了所有线程」——后者调再大也没用。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











