swoole本身不内置负载均衡逻辑,worker_num仅控制单机进程级并发调度,无法实现多实例流量分发、健康感知、故障转移及连接粘性等需求;真正的负载均衡必须依赖nginx、haproxy等外部反向代理或应用层客户端lb。

直接说结论:Swoole 本身不内置负载均衡逻辑,Swoole\Http\Server 或 Swoole\Server 的 worker_num 是进程级并发调度,不是服务间流量分发;真正的负载均衡必须靠外部组件(如 Nginx、HAProxy)或在应用层手动实现客户端 LB。
为什么不能只靠 Swoole 的 worker_num?
worker_num 控制的是单个 Swoole 进程内有多少个工作子进程处理请求,属于「单机内部分发」,和「多实例之间分摊流量」完全不是一回事。它解决不了以下问题:
- 单点故障:一个 Swoole 实例挂了,整个服务就不可用
- 横向扩展:无法把请求打到另一台机器上的 Swoole 实例
- 健康感知:worker 进程崩溃后,Swoole 会自动重启,但上游并不知道这个波动
- 连接复用与粘性:比如 WebSocket 场景下,客户端必须固定连接到同一个后端,
worker_num完全不参与这个决策
Nginx upstream 是最常用且靠谱的方案
绝大多数生产环境都用 Nginx 做反向代理 + 负载均衡入口,因为它稳定、配置直观、支持健康检查。关键点不是“能不能配”,而是“怎么配才不出错”:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- HTTP 服务必须加
proxy_http_version 1.1和proxy_set_header Upgrade $http_upgrade,否则 WebSocket 握手直接失败 - 长连接要配
proxy_set_header Connection "upgrade"和keepalive 32,不然每个请求都重建 TCP,压垮 Swoole 的 reactor 线程 -
max_fails=3 fail_timeout=30s是底线配置,只设max_fails=1容易因瞬时抖动误判节点宕机 - 如果 Swoole 启用了 HTTPS(比如用
Swoole\Http\Server+ SSL),Nginx 必须终止 TLS,不能透传;否则 PHP 里$_SERVER['HTTPS']永远是空,$_SERVER['HTTP_X_FORWARDED_PROTO']也拿不到
自己写客户端负载均衡器(Client-side LB)适合什么场景?
当你的架构中存在「服务调用服务」(比如 Swoole 微服务之间 RPC),又不想引入 Nginx 单点依赖时,可以在 PHP 代码里实现 LB 逻辑。这不是炫技,而是为了解耦和容错:
- 轮询(
roundRobin)够用就别上加权:多数内部服务性能接近,平滑加权算法(如 Nginx 的 SWRR)反而增加维护成本 - 节点存活判断不能只 ping 端口:得发一个轻量 HTTP 探针(比如
/health),并缓存结果 5–10 秒,避免每次请求都做 IO 判断 - 一致性哈希只在有本地缓存/Session 绑定需求时启用,比如用户 session 存在内存里,必须保证同一用户始终落到同一台机器
- 不要在
onRequest里每次都 new LoadBalancer:应作为单例注入或静态持有,避免重复初始化节点列表和权重状态
最容易被忽略的点:Swoole 实例本身的健康暴露
无论你用 Nginx 还是自研 LB,后端 Swoole 实例必须主动提供可探测的健康接口。很多人只写了业务逻辑,忘了加 /health,导致 LB 一直认为它活着,其实已经卡死在某个协程里了。最简实现就是:
$http->on('request', function ($request, $response) {
if ($request->server['request_uri'] === '/health') {
$response->header('Content-Type', 'text/plain');
$response->end('ok');
return;
}
// ... 正常业务
});
这个接口必须不依赖数据库、Redis 或任何外部 IO —— 否则健康检查本身就会失败,形成负反馈循环。真正难的从来不是怎么转发请求,而是怎么让整个链路里的每个环节都可观察、可退化、可快速恢复。










