vegeta是唯一可信的FrankenPHP长时HTTP/2压测工具,因其支持HTTP/2、响应体校验和结构化延迟分析;需用-include-body和-http2参数,并配合/fpm-status与/phpinfo实时监控worker阻塞、队列堆积及OPcache OOM重启。

用 vegeta 跑长时 HTTP/2 压测,别用 ab 或 wrk
ab 和 wrk 默认走 HTTP/1.1 且不校验响应体,FrankenPHP 在 HTTP/2 下复用连接、共享 PHP worker 生命周期,ab 每次请求都模拟全新 CGI 上下文,测出来的是“启动抖动”而非真实稳定性。vegeta 支持 HTTP/2、可捕获完整响应体用于断言、输出结构化延迟分布,是唯一能暴露 FrankenPHP 长期运行问题的 CLI 工具。
必须加 -http2 和 -include-body,否则看不到 500 错误或 JSON 格式异常:
vegeta attack -targets=targets.txt -rate=50 -duration=5m -http2 -include-body
其中 targets.txt 内容为:GET http://localhost:8000/api/health
- 速率设
-rate=50(非峰值)更易暴露缓慢累积的问题,比如内存泄漏或 OPcache 失效 - 持续时间至少
5m:FrankenPHP 的max_requests默认 1000,短于 3 分钟可能压不到 worker 重启边界 - 务必用
/api/health这类轻量 endpoint,避免 DB 或外部依赖干扰判断
实时盯 /frankenphp/phpinfo 和 /fpm-status?json
光看 vegeta 的 errors 字段不够——它只统计连接失败或超时,而 FrankenPHP 常见的稳定性故障是 worker 卡死、队列堆积、OPcache OOM 重启,这些不会直接返回 HTTP 错误码,但会体现在运行时指标里。
开一个终端持续轮询:
立即学习“PHP免费学习笔记(深入)”;
watch -n 1 'curl -s http://localhost:8000/fpm-status?json | jq ".active_workers, .queue_length"'
同时另一个终端查 PHP 状态:
watch -n 1 'curl -s http://localhost:8000/frankenphp/phpinfo | grep -A2 "opcache.memory_usage.used_memory\|oom_restarts"'
-
queue_length > 0持续超过 10 秒 → worker 阻塞,不是 CPU 不够,而是某请求卡在 I/O 或锁上 -
oom_restarts数值在压测中跳变 → OPcache 内存不足,需调大opcache.memory_consumption或检查缓存键膨胀 -
used_memory占比长期 opcache.validate_timestamps=1 导致频繁重编译
在 Kernel::terminate() 里埋点验证生命周期完整性
FrankenPHP 的稳定性优势不在“不崩”,而在“异步逻辑真执行”。Laravel 的 terminate() 回调、日志刷盘、队列推送等行为,在传统 FPM 下由子进程自然退出触发;FrankenPHP 的常驻 worker 若信号处理异常或 GC 延迟,这些回调可能静默丢失——压测 QPS 再高也白搭。
在 App\Http\Kernel.php 的 terminate() 方法里加一行:
file_put_contents('/tmp/terminate.log', date('H:i:s') . "\n", FILE_APPEND);
压测结束后立刻检查:
-
wc -l /tmp/terminate.log应 ≈ vegeta 发起请求数(允许 ±2% 浮动) - 若明显偏少(如 1000 请求只记录 600 行)→ worker 未正确执行 terminate,大概率是
max_requests设置过小 + 重启时未等待回调完成 - 若行数正常但时间戳集中在某几秒 → 所有 worker 同步重启,说明
max_requests设得过于整除,应改用随机偏移(如 987)避免雪崩
检查错误日志里的隐性警告是否随时间恶化
很多 FrankenPHP 稳定性问题不表现为崩溃,而是 PHP warning 在 worker 长期运行中缓慢放大:比如 Undefined array key 触发的临时哈希表重建、Trying to access array offset on value of type bool 引发的额外类型推导开销。单次请求看不出,1000 次后延迟就飘了。
压测中实时 tail 日志并过滤 warning:
tail -f /var/log/php_errors.log | grep -i "warning\|notice"
- 若 warning 出现频率随压测时间线性上升 → 全局变量污染或静态属性未重置,需检查中间件或服务提供者
- 若每 500–1000 请求集中爆发一次
Allowed memory size exhausted→max_requests到期前内存已逼近上限,应结合memory_get_peak_usage(true)打点确认泄漏点 - 出现
Worker #X restarted after max_requests但间隔远小于预期 → 可能被opcache_reset()或其他强制 reload 动作干扰,检查是否有定时任务或热更新脚本
稳定性不是“没报错”,而是所有异步路径在 worker 生命周期内都被可靠执行,且资源释放节奏可控。FrankenPHP 把进程管理从运维问题变成了配置+埋点问题,漏掉任何一层,压测数据都只是幻觉。



















