FrankenPHP Worker 数量需根据 Symfony 实际负载下的 frankenphp_worker_busy 和 frankenphp_worker_ready 指标动态校准,而非按 CPU 或内存理论换算;busy 长期超 total 的 80% 表明不足,ready 长期超 50% 且队列仍高则提示启动阻塞。

Worker 数量取决于 Symfony 应用的并发请求特征,不是 CPU 核心数或内存大小直接换算
FrankenPHP 的 Worker 模式下,每个 worker 实例会独占一个 PHP 线程并长期驻留,反复处理请求。对 Symfony 这类框架来说,Worker 数设得太少会导致请求排队(frankenphp_queue_depth 上升),设得太多则可能触发内存溢出或 GC 压力——尤其当应用用了 Doctrine 缓存、EventDispatcher 或长生命周期服务时。
关键判断依据是实际负载下的 frankenphp_worker_busy 和 frankenphp_worker_ready 指标趋势,而不是理论值。
怎么查当前 Worker 的真实压力?
先确认 Caddy metrics 已启用(否则所有指标为 0):
-
frankenphp_worker_busy{worker="your-worker-name"}:当前正在处理请求的该 Worker 实例数 -
frankenphp_worker_ready{worker="your-worker-name"}:已启动、空闲待命的实例数 -
frankenphp_worker_total{worker="your-worker-name"}:该 Worker 当前总实例数(= busy + ready + crashed + restarting) - 如果
busy长期 > 80% 的total,说明实例不足;如果ready长期 > 50% 的total且queue_depth仍高,说明 Worker 启动慢或阻塞在初始化阶段(比如 Doctrine Proxy 生成、容器编译)
Symfony Worker 启动慢的常见卡点
Symfony 应用在 Worker 初始化阶段(即每次新 Worker 进程启动时)会执行完整容器构建和缓存预热,这个过程不可并发复用。以下情况会让单个 Worker 启动耗时显著增加:
立即学习“PHP免费学习笔记(深入)”;
- 启用了
debug:container或未禁用开发模式配置(APP_DEBUG=1) - Doctrine 实体映射复杂,且未预生成 Proxy 类(
doctrine:proxy:generate未跑或缓存失效) - 自定义 Kernel 中有同步 HTTP 调用、文件扫描或数据库连接检查
- 使用了
cache.adapter.redis_tag_aware但 Redis 连接池未预热,首次调用阻塞
这些都会导致 FrankenPHP 在 autoscaling 时不敢快速拉起新 Worker,表现为 frankenphp_worker_total 上升缓慢,而 queue_depth 持续堆积。
推荐起始配置与调优节奏
不要一上来就设 max_workers: 50。从保守值开始,靠指标反馈逐步放开:
- 新上线 Symfony Worker,先设
min_workers: 2,max_workers: 4 - 压测时观察 5 分钟内
frankenphp_worker_busy{worker="symfony"}的 P95 值;若常 > 3.5,再加max_workers到 6 - 每次调大后,盯住
frankenphp_total_threads和进程 RSS 内存:FrankenPHP 默认每个线程基础占用 ~30–50MB(含 Symfony 容器),超 80MB/线程需查内存泄漏 - 如果
frankenphp_worker_crashed_total{worker="symfony"}非零,优先看 Worker 日志里的Fatal error或Allowed memory size exhausted,而不是加数量
真正稳的 Worker 数,是让 busy 在峰值时稳定在 total × 0.6~0.8 区间,且没有持续 crash 或 OOM —— 这个数字因 Symfony 版本、Bundle 组合、数据层调用模式差异极大,没法套公式,只能靠 frankenphp_worker_* 系列指标实测校准。



















