是。vegeta 的 errors 字段出现大量 "context deadline exceeded" 表明 php worker 队列已满,请求无法进入执行阶段,而非网络超时。

看 vegeta 的 errors 字段是不是 context deadline exceeded
FrankenPHP 压测时,真正卡住的信号不是 QPS 下降或延迟飙升,而是 vegeta report -type=json 输出里 errors 字段大量出现 "context deadline exceeded"。这不是网络超时,是 PHP worker 队列满、请求进不去执行阶段的明确标志。
常见误判场景:
- 用
wrk看到延迟从 20ms 涨到 800ms,就以为是 FrankenPHP 慢了——其实只是队列积压,active_workers已满,新请求在等空闲 worker -
curl -s http://localhost:8000/fpm-status?json返回"queue_length": 42,但"active_workers": 8(已达php_worker配置上限),说明瓶颈在 worker 数量,不是代码或 DB - 错误地把
opcache.oom_restarts上升归因为内存不足,其实是 worker 长时间阻塞导致 OPcache 缓存无法刷新,触发强制重启
对比 frankenphp status 和系统级指标是否脱节
FrankenPHP 自带的 frankenphp status 显示 workers: 8/8、queue: 0,但 htop 里 Go 进程 CPU 占用只有 12%,同时 netstat -an | grep :8000 | wc -l 显示 ESTABLISHED 连接数卡在 1024 —— 这说明瓶颈不在 PHP 层,而在系统连接数限制或 Caddy 的 TLS 握手能力。
关键检查点:
- 运行
ulimit -n,确认不是被 shell 级文件描述符限制卡住(FrankenPHP 默认需 ≥ 65536) - 检查 Caddyfile 是否启用了
http3,HTTP/3 在高并发下会显著增加 Go runtime 的 goroutine 开销,GOMAXPROCS设太低会导致握手排队 - 用
ss -s看tw(TIME_WAIT)连接是否堆积,大量短连接未及时回收会挤占端口
用 terminate() 埋点验证请求是否真执行完
Laravel 或 Symfony 应用里,光看 HTTP 状态码 200 和响应时间,不能证明整个请求生命周期走完了。FrankenPHP 的 worker 模式下,若 Kernel::terminate() 没触发,意味着队列监听、日志刷盘、异步通知等逻辑全部丢失——但压测工具完全感知不到。
实操判断法:
- 在
App\Http\Kernel::terminate()里加file_put_contents('/tmp/terminate.log', 'x', FILE_APPEND) - 压测后执行
wc -l /tmp/terminate.log,若结果远小于请求总数(比如发了 3000 请求,log 只有 42 行),说明 worker 在某处挂起或被 SIGTERM 强杀,根本没走到 terminate 阶段 - 此时
vegeta报告可能显示 0 errors、95% 延迟正常,但业务已静默丢数据
禁用 OPcache 后 QPS 反而上升,说明之前测的是缓存假象
执行 frankenphp php-cli -r "opcache_reset();" 后立刻压测,如果 QPS 比之前高,说明上一轮测的全是 OPcache 命中,根本没跑 PHP 逻辑。典型表现是:用 /api/status 路由压测时,QPS 高得离谱,但换一个动态生成 JSON 的路由(如 /api/users/random)就断崖下跌。
必须同步验证的两件事:
- 确认压测路径真实触发 PHP 执行:在路由 handler 开头加
file_put_contents('/tmp/hit.log', '1', FILE_APPEND),压测后检查行数是否匹配 - 检查
opcache_get_status()['scripts']里目标脚本是否在列表中,且hits值远大于misses——若没命中,说明路径被 Caddy 当静态文件处理了
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











