canal实现mysql→es增量同步需满足三前提:mysql开启row格式binlog(log-bin=mysql-bin、binlog-format=row、server_id=1)、授予canal用户select/replication slave/replication client权限、使用canal-adapter配置es7.yml(_type必须为_doc、_id须显式映射、字段类型需es提前定义)。

Canal 是目前最稳妥、可运维性最强的 MySQL → ES 增量同步方案,前提是 MySQL 已开启 ROW 格式 binlog 且权限配置正确;跳过这步直接配 Canal,90% 的失败都卡在这里。
MySQL 5.7 必须确认的三项 binlog 配置
Canal 依赖 MySQL 主从复制协议,不是“连上就能读”,它需要真实可用的 binlog 流。以下三处缺一不可:
-
log-bin=mysql-bin:必须显式启用,不能只写log_bin=ON(MySQL 不认) -
binlog-format=ROW:STATEMENT或MIXED模式下 Canal 无法解析 DML 变更内容,会丢数据 -
server_id=1:值必须是整数且全局唯一;若 Canal Server 的canal.instance.mysql.slaveId也设为 1,启动时会报SlaveIdConflict
验证命令必须在 MySQL 客户端中执行:
SHOW VARIABLES LIKE 'log_bin'; -- 返回 ON 才生效<br>SHOW VARIABLES LIKE 'binlog_format'; -- 必须是 ROW<br>SHOW MASTER STATUS; -- 能查到 File 和 Position 才说明 binlog 正常写入
Canal Server 启动前要绕开的两个权限坑
Canal 连接 MySQL 用的是普通账号,但权限要求比业务账号高得多。常见错误是只给了 SELECT,漏掉关键复制权限:
- 必须显式授予
REPLICATION SLAVE(不是REPLICATION CLIENT单独就能行) - 用户 host 不能写成
'canal'@'localhost'—— Canal Server 通常不在 MySQL 容器内运行,得用'canal'@'%'或具体 IP - 如果 MySQL 开了
sql_mode=STRICT_TRANS_TABLES,而 Canal 解析到空字符串插入非空字段,会触发同步中断(日志里报java.sql.SQLException: Data truncation)
建用户推荐语句:
CREATE USER 'canal'@'%' IDENTIFIED BY 'canal';<br>GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';<br>FLUSH PRIVILEGES;
canal-adapter 同步到 ES 7.x 的关键映射配置
Canal Server 只负责把 binlog 解析成 JSON 事件,真正写 ES 是 canal-adapter 干的。ES 7.x 废除了 _type,但早期 canal-adapter 模板仍默认带 type: _doc,会导致 bulk 写入失败,报错:illegal_argument_exception: Rejecting mapping update to [xxx] as the final mapping would have more than 1 type。
- 删掉
application.yml中所有type:字段(包括esMapping._type和模板里的"_type": "_doc") -
esMapping._id必须指向一个 MySQL 表字段,比如id;若写成pk且表没主键,会 fallback 到 UUID,导致重复文档 - ES 索引名默认小写,但 MySQL 表名可能含大写;建议在
esMapping.sql中用反引号明确字段,如SELECT `id`, `title` FROM `user_info`
最小可用 esMapping 片段示例:
esMapping:<br> _index: user_index<br> _id: _id<br> sql: "SELECT a.id AS _id, a.name, a.content FROM user_info a"
同步延迟高或断连时优先检查这三点
Canal 同步不是“配完就稳”,生产环境常见抖动点集中在网络、序列化和 ES 批处理上:
- MySQL 端
max_allowed_packet太小(默认 4MB),遇到大文本字段的 UPDATE 会截断 binlog,Canal 解析失败后卡住;建议调到64M - Canal Server 的
canal.instance.memory.buffer.size默认 16MB,高并发下 buffer 溢出导致丢 event;观察日志是否有buffer overflow - canal-adapter 的
batchSize设太大(如 5000+),ES bulk 请求超时(默认 1m),会反复重试并拖慢整体吞吐;建议先设为1000,再按 ES 集群负载调优
真正难调试的,永远是 MySQL binlog 与 Canal 消费 offset 之间的“看不见的差值”——一旦 Canal 因异常重启,它靠 meta.dat 恢复位置,但这个文件若被误删或写入失败,就会从头重放或跳过部分变更,必须定期核对 canal-server/logs/example/example.log 里的 ack 记录和 MySQL SHOW MASTER STATUS 的 Position 是否追平。











