reuseport在长连接场景下虽不显著缓解惊群(因accept极少触发),但仍建议开启:一可应对混杂短连接请求,二能实现内核级更均衡的连接分发;需linux 3.9+、php≥7.0且正确配置监听地址。

长连接下惊群效应其实不显著,但 reusePort 仍值得开
Workerman 的惊群效应主要发生在 accept() 阶段,也就是新 TCP 连接建立的瞬间。对长连接应用(如 WebSocket、IM 聊天室),绝大多数连接只在启动时建立一次,后续通信复用该连接,不再触发 accept() —— 所以惊群实际影响极小。
但 reusePort 仍建议开启,原因有二:一是短连接混杂场景(比如同一端口同时提供 HTTP 短请求 + WebSocket 长连接)中,短连接部分仍会触发惊群;二是内核级负载分发更均匀,避免某些 Worker 进程长期空闲而另一些过载。
容易踩的坑:
-
reusePort仅在 Linux 3.9+ 内核生效,低于此版本会静默忽略,不报错也不起作用 - 开启后,
stream_socket_server()必须在每个子进程里独立调用(Workerman 默认已做到),不能只由主进程创建再 fork 继承 - 若使用 Docker,需确认容器运行的宿主机内核版本,而非容器内
uname -r显示的版本(可能被伪装)
Workerman 中 reusePort 的真实启用条件
Workerman 并非只要设置 $worker->reusePort = true 就一定生效。它依赖底层 PHP stream context 的 socket 选项传递,且受运行时环境约束。
关键判断点:
- 必须使用
tcp或udp协议,unix域套接字不支持SO_REUSEPORT - 监听地址不能是
127.0.0.1或::1的 loopback 特定绑定,推荐用0.0.0.0:port或[::]:port - PHP 编译时需启用 sockets 扩展,且运行时未被禁用(检查
ini_get('disable_functions')是否含socket_create) - 若启用了 SELinux,需确认策略允许
bind多次到同一端口(常见于 CentOS/RHEL)
验证是否生效最直接的方式是启动后执行:ss -tlnp | grep :your_port,看到多行输出(每行对应一个 Worker 进程的 PID),说明 SO_REUSEPORT 已成功启用。
为什么长连接仍要配心跳?和惊群无关,但常被混淆
很多人把“连接断连没人发现”误认为是惊群导致的,其实完全不是一回事。惊群只影响新连接接入,不影响已有连接的存活状态。
长连接失效的真实原因是 NAT 超时、防火墙保活策略、客户端异常掉线等,这些都发生在连接建立之后,与 accept() 完全无关。
所以 Workerman 必须自己维护 lastMessageTime 并定时扫描,否则:
- 服务器无法感知客户端已静默断开,连接对象持续占用内存和 fd
- 客户端重连时可能因旧连接未释放而触发服务端资源耗尽
- 即使开了
reusePort,无效连接堆积也会拖慢整个事件循环响应速度
典型配置示例(WebSocket 场景):
onWorkerStart: function($worker) {
// 每 45 秒检查一次连接活跃度
\Workerman\Timer::add(45, function() {
$timeNow = time();
foreach ($worker->connections as $connection) {
if (isset($connection->lastMessageTime) &&
$timeNow - $connection->lastMessageTime > 60) {
$connection->close();
}
}
});
}
真正影响长连接性能的,是事件循环阻塞,不是惊群
当开发者在 onMessage 回调里做同步 MySQL 查询、sleep、文件读写等操作时,整个 Worker 的事件循环会被卡住,所有该进程负责的长连接都会延迟响应 —— 这才是长连接场景下更隐蔽、更常见的性能瓶颈。
对比来看:
- 惊群:只在连接建立瞬间发生,长连接下几乎可忽略
- 阻塞操作:每次消息到达都可能触发,直接影响所有复用该连接的后续交互
解决路径很明确:把耗时操作移到异步上下文,例如:
- 数据库用
workerman/mysql或amphp/mysql异步驱动 - HTTP 请求用
GuzzleHttp\Ring\Client\StreamHandler+ event-loop 集成 - 避免在回调中调用
file_get_contents、curl_exec等同步函数
reusePort 解决的是“谁来 accept”,而事件循环不阻塞解决的是“accept 后谁来及时处理”。后者对长连接体验的影响,远大于前者。











