Nacos长轮询引发连接泄露主因是SDK协程不安全及连接未显式释放。旧版nacos-sdk-php(v2.2.x前)未绑定Client至协程生命周期,v2.5.0+引入ConnectionPool并强制复用、主动close;需同步升级hyperf/config-nacos至v3.1.0+,禁用auto_reconnect,手动在ConfigChanged事件中调用close(),并通过lsof验证socket真实释放状态。

为什么Nacos长轮询会引发连接泄露
Hyperf 启动后,NacosDriver 会持续发起 HTTP 长轮询请求(如 /v1/cs/configs/listener),每个请求默认阻塞 30 秒。若 SDK 未正确复用连接、未设置超时或未释放底层 cURL / Swoole\Coroutine\Http\Client 实例,就可能在高并发或网络抖动时积累大量未关闭的 socket 连接 —— 表现为 Worker 内存缓慢上涨、netstat -an | grep :8848 | wc -l 持续增加,但无明显报错。
升级 nacos-sdk-php 到 v2.5.0+ 是硬性前提
旧版 nacos-sdk-php(如 v2.2.x 及更早)存在协程安全缺陷:长轮询回调中新建的 Client 实例未绑定当前协程生命周期,导致连接无法被自动回收。v2.5.0 起强制使用 Swoole\Coroutine\Http\Client 并引入 ConnectionPool 管理长轮询客户端,关键修复包括:
- 每次长轮询复用池内 Client,避免重复
new - 监听到配置变更后主动调用
$client->close(),而非依赖 GC - 对
onError/onClose回调做协程上下文隔离,防止跨协程污染
执行升级命令:
composer update hyperf/nacos-sdk-php:^2.5.0注意:必须同时升级
hyperf/config-nacos 至 v3.1.0+,否则驱动层不兼容新 SDK 的 ListenerManager 接口。
必须关闭长轮询自动重试并手动控制连接生命周期
即使升级了 SDK,若保留默认的无限重试逻辑(如失败后立即重发 /listener),仍可能因瞬时网络故障堆积连接。需在配置中显式约束:
- 设
'retry_times' => 3,超过后暂停监听,避免雪崩 - 禁用自动恢复:
'auto_reconnect' => false,改由ConfigChanged事件触发重建 - 在
NacosConfigChangedListener中主动销毁旧 client:$container->get(\Hyperf\ConfigNacos\Client::class)->close();
错误做法是依赖 SDK 自动重连 —— 它不感知 Hyperf Worker 生命周期,重启前残留连接不会被清理。
验证连接是否真正释放
别只看日志有没有 “listener closed”,要查真实 socket 状态。在问题复现后,进入对应 Worker 进程执行:
lsof -p {pid} | grep ':8848' | wc -l
正常应稳定在 1~2 个(当前活跃长轮询 + 可能的健康检查)。若持续 >5 且随时间增长,说明仍有连接未 close。此时检查:
- 是否在自定义
UpdateConfigListener中手动 new 了Client但没调close() - 是否启用了
opcache.enable_cli=1导致类重载失效,旧 client 实例被缓存 - 是否在
onWorkerStop事件里漏掉了Client::close()调用
长轮询不是“开箱即用”的功能,它把连接管理权交还给了你 —— SDK 升级只是移除了最危险的坑,真正的释放逻辑必须由业务侧收口。


















