workerman实现数据实时同步的核心是建立稳定长连接、避免阻塞主线程、精准广播到目标客户端并确保多进程状态一致:通过websocket://协议监听端口,用redis或swoole\table实现跨进程广播,onmessage仅做轻量解析与入队,由定时器驱动消费redis队列并差分推送。

Workerman实现数据实时同步功能,核心是建立稳定长连接、避免阻塞主线程、精准广播到目标客户端,并确保多进程间状态一致。它不依赖轮询,也不在onMessage里做耗时操作,而是靠定时器驱动+外置存储协调完成毫秒级推送。
启动WebSocket服务并维护连接池
用WebSocket协议监听端口,让前端通过ws://协议建立持久连接。
创建Worker实例,绑定websocket://0.0.0.0:2345,设置$worker->count = 4启用多进程。
在onConnect回调中为每个连接分配唯一ID,并将其存入全局数组$worker->connections;这一步必须做,否则后续无法遍历推送。
注意:PHP数组$worker->connections只在当前进程内有效,【跨进程广播必须用Redis或Swoole\Table】,否则其他进程里的连接收不到消息。
接收数据并触发同步逻辑
前端发送JSON格式数据,例如{"type":"update","key":"stock_600519","value":1892.5}。
onMessage中先json_decode校验结构,再提取type和key字段——若type非预设值(如"update"、"delete"、"sync"),直接return跳过处理。
不要在onMessage里查数据库或调外部API,否则会阻塞整个进程,导致其他连接卡顿甚至超时断开。
正确做法是把解析后的数据推入Redis队列:$redis->lPush('sync_queue', $data_json);然后由独立的Consumer Worker消费该队列。
定时广播最新数据给在线客户端
第一步:用Worker\Timer::add()注册每100ms执行一次的定时任务。
第二步:从Redis读取最新同步状态,例如GET sync:stock_600519 或 HGETALL sync:status。
第三步:遍历所有在线连接,对每个$connection调用$connection->send($payload),但需跳过发送源本身——if ($connection === $source_conn) continue;。
第四步:广播前做轻量差分,比如只推送price变动超过0.01的数据,避免无效流量压垮带宽。
第五步:对广播失败的连接执行$connection->close(),防止ghost连接持续占用资源。
多进程房间隔离与跨进程状态同步
方法一:使用Redis pub/sub机制
当某进程收到更新指令,先PUBLISH sync:topic:stock_600519 '{"price":1892.5}',所有Worker进程订阅该channel,收到后各自向本进程内的对应连接推送。
方法二:使用Swoole\Table内存表(需已安装Swoole扩展)
初始化共享表$table = new Swoole\Table(4096); $table->column('fd', Table::TYPE_INT); $table->column('room_id', Table::TYPE_STRING, 64); $table->create(); 各进程写入时自动跨进程可见。
方法三:用Redis ZSET管理连接活跃度
每次onConnect时ZADD connections:stock_600519 time() fd,定时任务ZREVRANGEBYSCORE取最新100个fd,再逐个推送——适合按业务键动态分组的场景。
前端接收并应用增量更新
WebSocket onmessage事件中,解析JSON,检查是否含timestamp字段;若缺失或偏差超过5秒,则丢弃该条数据,防止时间错乱导致K线错位或库存覆盖。
拿到value后,不全量重绘DOM,而是用document.getElementById(key).textContent = value更新对应节点。
对于列表类数据,前端维护一个Map











