webman 不能直接集成 canal 客户端,因其 java sdk 依赖 jvm 和 netty,与 php 运行环境隔离;正确做法是通过 kafka/rocketmq 解耦消费,或极谨慎地手动实现 tcp 协议交互。

Webman 本身不内置 Canal 客户端能力,必须通过 Java 客户端桥接或独立服务解耦来实现 MySQL 增量订阅;直接在 PHP 进程里“集成”Canal 是错的路径。
为什么不能在 Webman 中直接运行 Canal 客户端
Canal 官方 SDK 是纯 Java 实现(canal.client、canal.protocol),依赖 JVM 和 Netty 等底层网络栈。Webman 是基于 ReactPHP 的 PHP 框架,两者运行时环境完全隔离——PHP 进程无法加载 .jar、调用 Java 类、处理 binlog byte 流解析逻辑,也做不到长连接保活、位点 Ack、异常 rollback 等 Canal 协议必需行为。
常见错误现象包括:
- 尝试用
exec('java -jar canal-client.jar')启动,进程闪退或无日志输出 - 用 PHP socket 手动连 Canal Server 的 11111 端口,收不到任何有效响应(协议不兼容)
- 误以为 Canal Server 是 HTTP 接口,发 GET 请求返回 404 或空响应
正确做法:把 Canal 当作独立下游服务接入
Webman 应专注业务逻辑和事件消费,Canal 负责协议解析与数据投递。二者之间必须通过标准中间件解耦,推荐 Kafka 或 RocketMQ:
- Canal Server 配置
canal.mq.topic和canal.mq.servers,将解析后的Entry推送到 Kafka Topic - Webman 使用
php-kafka(如rdkafka扩展)或rocketmq-client-php订阅该 Topic - 消费时按
Entry.header.table和RowChange.eventType分流处理(如INSERT写 Redis,UPDATE触发 ES 同步) - 务必在消费成功后提交 offset,避免重复消费;不要依赖 Canal 的
ack,因为 Webman 不直连 Canal Server
如果坚持要 PHP 直连 Canal Server(不推荐但可行)
只能走 Canal 提供的 TCP 协议网关(CanalTCPClient 行为),需自行封装二进制协议交互。这不是“集成”,而是重写客户端核心逻辑:
- 连接 Canal Server 的
11111端口,先发送Handshake包(含clientId),再发Subscribe(指定destination和filter) - 接收响应后,循环调用
GetWithoutAck,解析返回的 Protocol Buffer 数据(需google/protobuf+ 自定义.proto文件) - 手动处理
Message中的entries,逐个 decodeRowChange,提取beforeColumns/afterColumns - 每次成功处理后,必须调用
Ack并传入正确的batchId,否则 Canal Server 会重推该批次
这个路径极易出错:PHP 的 PB 解析易丢字段、TCP 心跳超时未处理、位点跳跃导致漏数据——线上几乎没人这么干。
最容易被忽略的三个点
一是 MySQL 的 server_id 和 Canal 的 slaveId 必须不同,否则主库拒绝 dump 请求;二是 Canal instance 的 filter 配置(如 test\.user)必须用双反斜杠转义点号,PHP 字符串里写成 'test\.user';三是 Webman 的 Worker 进程重启时,Kafka consumer group 会 rebalance,需确保消息处理是幂等的——别指望靠 Canal 的位点机制兜底。











