真正能拉开差距的是对连接生命周期、协程资源边界和长连接稳定性的精细把控:onclose需清理变量与资源;协程中禁用同步阻塞调用;websocket心跳参数须两端匹配;协程池须设限防雪崩。

真正能拉开差距的不是“会用 Swoole 启动一个 HTTP 服务”,而是你能否在连接生命周期、协程资源边界、长连接稳定性这些地方踩准节奏、提前设防。
onClose 回调里不清理变量,内存就只增不减
很多人写 onClose 只是打印一句日志,或者啥也不做。但 Swoole 进程常驻内存,$server->connections[$fd] 里存的用户上下文、Redis 连接句柄、临时缓存数组,只要没 unset,就会一直占着内存。
实操建议:
- 在
onClose中显式unset($server->connections[$fd]),并销毁关联的Co\Channel、Co\Socket实例 - 如果用了 Redis 连接池,确保该连接已归还(比如调用
$pool->put($redis)) - 避免在
onClose里再发起协程或远程调用——此时连接已断,容易触发异常或超时堆积
协程中混用普通 sleep 或 file_get_contents 就等于阻塞整个进程
常见错误现象:co::sleep(0.1) 写成 sleep(1),或在协程里直接调用 file_get_contents('http://api.com'),结果整个 Worker 进程卡死,后续所有请求排队等待。
原因很简单:Swoole 的协程调度依赖「可挂起的 IO 操作」,而 sleep() 和同步 HTTP 请求都是系统级阻塞调用,协程无法让出控制权。
实操建议:
- 所有延时统一用
co::sleep(),所有网络请求走Swoole\Coroutine\Http\Client或Co\Redis - 第三方 SDK(比如 Guzzle)默认不支持协程,必须替换为
swoole_http_client或加Co\run()包裹 + 异步适配层 - 本地文件读写尽量避免,非用不可时改用
Co\File或异步Co\Process隔离
WebSocket 心跳超时设置不匹配,客户端频繁重连
典型表现:前端 WebSocket 连接看似正常,但隔几十秒就触发 onClose,$server->stats() 显示大量 close_count 上涨,而 connection_num 波动剧烈。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
根本问题在于两端心跳节奏不一致:浏览器默认不发 ping,服务端靠 heartbeat_idle_time 和 heartbeat_check_interval 判断是否踢人,但很多同学只调大了前者,忘了后者也要同步调整。
实操建议:
- 服务端配置至少设两处:
'heartbeat_idle_time' => 60(客户端 60 秒没消息就断)、'heartbeat_check_interval' => 25(每 25 秒扫一次) - 客户端必须主动发
ping(文本帧"ping"或空字节),不能只等服务端 push - 不要依赖
onMessage里的业务逻辑来刷新 last_time——Swoole 内部有独立心跳计时器,业务处理延迟不影响它
协程池没设上限,LLM 流式响应一卡全卡
当多个用户同时发问,每个 onMessage 都 go(function () { call_llm_api_stream(...) }),协程数瞬间飙到几百,CPU 调度开销激增,token 推送延迟从 20ms 拉到 2s+,甚至触发 coroutine limit reached 错误。
这不是 LLM 慢的问题,是协程无节制创建导致的 backpressure 缺失。
实操建议:
- 用
Swoole\Coroutine\Pool包一层 LLM 客户端,池大小建议设为 CPU 核数 × 2~4(比如 8 核机器设 16~32) - 获取连接时加超时:
$client = $pool->get(3.0),拿不到就return $response->end('服务忙'),别死等 - 流式返回中每推一个 token 后加
co::usleep(10000)(10ms),给调度器喘息时间,也防止客户端渲染过载
真正难的从来不是“怎么让 Swoole 跑起来”,而是你愿不愿意在 onClose 多写三行清理代码,在协程里多确认一次调用是否异步,在心跳配置里多核对两个数字——这些地方不显眼,但线上扛不住压的时候,最先崩的就是它们。










