Mercure压测不能用ab或wrk,因其仅支持HTTP/1.1短连接,无法模拟SSE长连接、重连、event-stream解析等行为;必须使用locust+sseclient-py或Node.js eventsource等专用工具。

FrankenPHP 的 Mercure 压测不能用 ab 或 wrk 直接测
ab 和 wrk 都是基于 HTTP/1.1 的请求驱动工具,而 Mercure 是基于 Server-Sent Events(SSE)或 WebSocket 的长连接、事件推送协议。它们发完一次请求就断开,根本无法模拟客户端持续监听 /mercure 事件流的行为。
直接拿 ab -n 1000 -c 100 http://localhost/.well-known/mercure 测,只会返回 405 或空响应——因为 Mercure endpoint 不接受普通 GET,它要的是带 Accept: text/event-stream 头、保持连接不关闭的客户端。
- ab 不支持保持连接监听 SSE 流,也不支持自定义 header 持久化
-
wrk默认启用 keep-alive,但不解析 event-stream 格式,也无法处理重连逻辑(如retry:指令) - 真实用户浏览器或移动端 SDK 会自动处理 reconnect、event type 分发、last-event-id 恢复,这些压测工具完全不模拟
必须用支持 SSE 的专用工具或手写脚本
目前最可行的方案只有两个:一是用 locust + Python 的 requests-toolbelt 或 sseclient-py 扩展;二是用 Node.js 的 eventsource 库写轻量级并发连接器。
推荐用 locust,因为能控并发数、连接生命周期、失败重试策略,还能统计每秒建立连接数、平均流存活时长、消息接收速率等关键指标。
立即学习“PHP免费学习笔记(深入)”;
- 安装:
pip install locust sseclient-py - locustfile.py 中需用
SSEClient实例发起连接,而非self.client.get() - 注意设置
stream=True和手动读取 response.iter_lines(),否则连接会立即关闭 - 每个用户实例应维持一个长连接,并在超时或断连后按 Mercure 规范重连(带
Last-Event-ID)
示例片段:
from sseclient import SSEClient
import time
<p>def connect_to_mercure(host, jwt_token):
url = f"{host}/.well-known/mercure"
headers = {
"Authorization": f"Bearer {jwt_token}",
"Accept": "text/event-stream"
}
client = SSEClient(url, headers=headers, retry=3000)
for event in client:
if event.data:
pass # 模拟消费事件</p>Mercure 压测真正要盯的不是 QPS,而是连接保有量和事件吞吐延迟
FrankenPHP 的 Mercure 实现跑在 Caddy 内部,底层复用 Go 的 net/http.Server 和 goroutine 调度,单机轻松支撑上万长连接。但瓶颈往往不在它本身,而在 PHP 应用层的事件分发逻辑、JWT 解析开销、或 Redis 订阅通道压力。
- 不要只看 “每秒推送多少条”,先确认
frankenphp mercure status输出里active_connections是否稳定增长到目标值 - 检查 Redis 的
INFO clients和INFO memory,Mercure 默认用 Redis Pub/Sub,连接数翻倍时 pubsub_channels 和 used_memory_rss 会明显跳升 - 如果用 FrankenPHP 自带的内置 Redis(非外部),注意
workers.count和redis.max_connections配置是否匹配,否则会出现connection refused而非超时 - JWT 过期时间太短(比如 30s)会导致客户端高频重鉴权,压测时看到大量 401 并非 Mercure 问题,而是 token 策略不合理
Docker 环境下容易漏掉的 Mercure 配置项
FrankenPHP 的 Mercure 功能默认不开启,即使你装了二进制、写了 Caddyfile,没显式启用 mercure 指令,/.well-known/mercure 就是 404。
- Caddyfile 中必须包含
mercure块,且路径要匹配:例如handle /.well-known/mercure* { mercure } - 环境变量
MERCURE_PUBLISHER_JWT_KEY和MERCURE_SUBSCRIBER_JWT_KEY必须通过environment注入容器,不能只写在 .env 里 - Docker Compose 启动时若用了
command: ["frankenphp", "server"],得确保没覆盖掉默认加载的 Caddyfile;建议显式挂载:volumes: ["./Caddyfile:/etc/caddy/Caddyfile"] - 本地开发用
frankenphp worker模式启动时,Mercure 不可用——它只在frankenphp server模式下由 Caddy 提供
压测前先 curl 一把 curl -H "Accept: text/event-stream" http://localhost/.well-known/mercure,看到持续冒 event 字段才算通。否则所有后续压测都是在测 404。



















