workerman 不支持分库分表自动发现与数据合并,仅作为网络通信管道;需依赖 binlog 解析或业务主动推送变更,并通过 redis 等中转实现多分片消息汇聚与统一推送。

Workerman 本身不直接支持分库分表的自动发现、路由或数据合并,它只是一个高性能 PHP 网络通信框架。你要实现「分库分表后的数据实时同步」,得明确一点:Workerman 是管道,不是数据库中间件 —— 它负责把变更消息推过去,但谁来捕获变更、谁来聚合多源数据、谁来保证顺序和一致性,得你自己补全。
分库分表变更怎么被 Workerman 感知到?
MySQL/PG 的分库分表本身是逻辑层切分,底层仍是多个独立实例。Workerman 没有内置 CDC(Change Data Capture)能力,必须依赖外部机制把变更“喂”进来:
-
binlog解析(如用maxwell、canal或debezium)监听各分片库的变更,再通过 HTTP/WebSocket 推给 Workerman 进程 - 各业务服务在写入分库分表时,主动调用 Workerman 提供的推送接口(比如
file_get_contents("@#@#@#@#@#@#@#@#@#@0=...")),需确保幂等和重试 - 不推荐轮询查表,延迟高、压力大、无法做到真正实时
注意:Workerman 的 onMessage 回调里收到的是原始变更消息,字段名、主键、分片键(如 user_id % 4)都得你自己解析,不能指望框架自动识别 order_01 和 order_02 是同一逻辑表。
多分片数据如何在 Workerman 里统一推送?
你不能让每个分片连一个 Workerman 实例 —— 这会导致客户端收不到跨分片的关联更新(比如用户 A 下单 + 库存扣减分别落在 order_03 和 stock_02,但客户端只连了其中一个服务)。
正确做法是:
- 所有分片的变更消息,统一汇聚到同一个 Workerman 主进程或一组共享内存/Redis 的 Worker 进程
- 使用
Redis的PUB/SUB或Stream做消息中转,避免进程间直连耦合 - 在推送前做轻量聚合:比如检测
order_id=123的订单创建和支付成功是否都已到达,再合并推给前端(需加业务层状态机,Workerman 不提供) - 客户端订阅时传参标识逻辑实体,例如 WebSocket 连接 URL 带
?biz_id=user_456,服务端据此过滤并推送该用户所有分片的相关变更
为什么不能直接用 Workerman 同步 MySQL 分表到目标表?
因为 Workerman 没有 SQL 解析、事务控制、冲突检测、断点续传这些能力:
- 它不理解
INSERT INTO order_01和INSERT INTO order_02共享同一套 DDL - 它不会帮你把
order_01的id和order_02的id映射回逻辑主键 - 它无法处理
DROP TABLE order_03这类 DDL 变更,更不会重建映射关系
如果你真需要「分库分表 → 单表」的实时同步,应该用 DataWorks 的脚本模式 + 自定义 reader 插件,或 Flink CDC 配合动态表路由,而不是硬塞给 Workerman。
Workerman 做同步时最容易被忽略的坑
-
Worker->connections是进程级变量,4 个子进程各自维护一份连接池 —— 你用foreach($worker->connections as $conn)只能推给本进程的客户端,跨进程要走Redis或Unix Socket - 没有内置 ACK 机制,WebSocket 断连后消息就丢了,得自己加消息队列(如
RabbitMQ)+ 客户端重连后拉取未读变更 - 分库分表场景下,时间戳可能来自不同数据库实例,
NTP不准会导致排序错乱,别直接按create_time排序合并 -
onClose回调不一定触发(比如客户端强制 kill 进程),连接清理得配合心跳 + 超时淘汰
分库分表的实时同步,本质是「分布式事件流编排」,Workerman 只解决最后一公里的低延迟投递。前面那几公里,得靠你设计清楚。











