Workerman跨多机协同必须依赖外部组件补足节点发现、任务分发与状态同步能力,其自身仅作为无状态执行端;调度逻辑须由独立服务承担,如Redis+BRPOP实现心跳注册与低延迟任务指派,并通过超时重入机制保障任务不丢。

要让Workerman服务能跨多台服务器协同工作,必须打破单机边界,用外部组件补足它缺失的节点发现、任务分发和状态同步能力;Workerman本身只负责高效执行,不承担调度职责。
明确角色分工:谁管调度,谁管干活
Workerman进程只能作为Worker(执行端),不能当Master(调度中心)。所有节点注册、心跳检测、任务分发、故障转移逻辑,必须由独立服务实现——比如一个单独的PHP脚本监听Redis,或一个用Swoole写的轻量调度器。
常见错误是把调度逻辑硬塞进Workerman进程里:比如让每个Worker定时file_get_contents拉任务URL。这会导致节点间完全无协调,任务重复抓取、漏执行、扩缩容时状态混乱。
【每个Workerman实例必须无状态】 所有会话、用户连接映射、任务进度等数据,一律存到Redis或MySQL,不能放在PHP变量或文件里。
部署负载均衡层,分散客户端连接
在所有Workerman服务器前加一层Nginx或HAProxy,把TCP/HTTP请求按策略分发过去。
若业务依赖长连接状态(如聊天室),必须开启负载均衡器的IP Hash或Session Sticky功能,否则用户连接会跳到不同机器,导致消息丢失或登录态失效。
更推荐的做法是彻底剥离状态:用户ID → Redis哈希槽映射,消息广播走Redis Pub/Sub,这样Workerman实例就能任意增减,无需粘性路由。
用Redis实现节点注册与心跳保活
第一步:每个Workerman节点启动时,向Redis SET写入唯一ID(如node:web-01)和IP+端口信息,并设置30秒过期。
第二步:节点内启一个Timer,每15秒刷新一次该KEY的EXPIRE时间,模拟心跳。
第三步:调度服务持续SCAN Redis中node:*的KEY,剔除超时未刷新的节点,动态维护在线节点列表。
注意:节点ID必须固定(从配置文件或环境变量读取),不能随机生成,否则任务发错队列后无法找回。
用BRPOP实现低延迟任务指派
方法一:为每个节点建专属队列
节点node-abc启动后执行:$task = $redis->brpop(['queue:node-abc'], 5);,阻塞最多5秒等待任务。
方法二:共用一个任务队列,靠竞争消费
所有节点监听同一LIST,用BRPOP tasks 5,谁抢到谁处理。适合任务粒度小、节点数不多的场景。
【BRPOP超时值不能设为0】 否则进程无法响应SIGTERM信号正常退出,容器重启会卡死。
保障任务不丢:依赖重入队,而非完成确认
第一步:调度服务从待抓队列(pending:url_list)弹出一个URL,包装成JSON,LPUSH到某节点私有队列(queue:node-001)。
第二步:节点消费后开始抓取,但不主动上报“已完成”——因为网络中断或进程崩溃时,上报会丢失。
第三步:调度服务每隔30秒扫描所有私有队列,若发现某任务在队列里停留超60秒,视为超时,自动LPUSH回pending:url_list重试。
这种“默认失败、主动兜底”机制比ACK模式更可靠,也省去了节点宕机后清理未确认任务的复杂逻辑。

















