Canal Adapter 自动同步失效之谜:从排查到重启解决的深度复盘

451 阅读10分钟

引言

记录一次线上环境 Canal Adapter 无法自动同步 MySQL 数据到 Elasticsearch 的故障排查过程。尽管手动调用 ETL 接口能同步数据,但 Binlog 变更事件始终未触发自动同步。最终通过 重启 Canal Adapter 服务 解决问题,本文将深入分析根因、完整排查逻辑及涉及的关键技术点。

背景

我们有一个曲库搜索,是通过Elasticsearch进行查询的,每一本教材包含很多曲谱,教材以及曲谱的上下架操作通过后台管理系统进行操作, 变更状态后,需要同步Elasticsearch,这样保证前端用户能查询到最新教材或者曲谱,最近出现了教材可以同步但曲谱没办法自动同步的现象, 我本人是一名测开,以前未接触过这方面知识,因此把排查过程详细记录,加深记忆。

问题现象

  • 环境:

    • MySQL(阿里云 RDS) + Canal Server + Canal Adapter + Elasticsearch
    • 同步表: books (正常) 和 sys_scores (失效)。
  • 表现:

    • 手动执行 /etl/es/ai_sys_scores.yml 接口同步成功。
    • 自动监听 Binlog 时, sys_scores 表数据变更未同步到 ES。
    • 日志无报错,Canal Server 和 Adapter 显示“运行正常”。

完整排查过程

基础检查

  1. 确认 Binlog 配置

    • 验证 MySQL 的 binlog_format=ROW 和 binlog_row_image=FULL

    • 解析 Binlog 确认 sys_scores 表变更已记录:
      更改曲谱上下架状态,然后执行,如下命令:

      SHOW MASTER STATUS;
      

      此命令可以得到binlog文件名称,我这里使用的阿里云RDS,登录控制台下载该文件到本地,然后执行如下命令

      mysqlbinlog --base64-output=decode-rows -v mysql-bin.000543 | grep "sys_scores"
      

      或者,也可以解析后,输出到文件,执行如下命令

      mysqlbinlog -vv --base64-output=decode-rows mysql-bin.000543 > output.sql
      

    结论 :Binlog 正常生成。 注意:针对阿里云 RDS for MySQL , 默认打开了 binlog , 并且账号默认具有 binlog dump 权限 , 不需要任何权限或者 binlog 设置

  2. 检查 Canal Adapter 配置

    • 确认 ai_sys_scores.yml 中:

      destination: ai_example  # 与 Canal 实例名一致
      _index: ai_scores_v2    # 索引存在
      sql: "SELECT id, status FROM sys_scores"
      

    结论 :配置无语法错误。

  3. 验证网络与权限

    • Canal Server 能连接 MySQL,Adapter 能连接 ES。
    • Canal 账号具备 REPLICATION SLAVE 权限。

深入排查

  1. 查看 Canal Server 实例配置文件,是否将sys_scores表过滤 打开目录下对应的 instance.properties 文件

    • 查找canal.instance.filter.regex配置:

      canal.instance.filter.regex 配置值为.*\..*

      结论:未过滤掉指定表

  2. 检查 Adapter 订阅状态

    • 调用 Canal Server 运维接口:

      echo "status" | nc 127.0.0.1 11112
      

      现象 :无响应 → Canal Server 运维端口未激活。

    • 解决 :修改 canal.properties 中 canal.admin.port=11112 并重启 Canal Server。

  3. 对比手动与自动同步差异

    • 手动 ETL :直接执行 SQL 查询 MySQL 当前数据,写入 ES。

    • 自动同步 :依赖 Binlog 事件,需满足:

      • Canal Server 捕获事件 → Adapter 接收事件 → ES 写入。

关键解决步骤

进行了上面所有检查,并没有发现问题所在,然后准备开启 Adapter 的 DEBUG 日志,看从更详细日志中能否发现端倪

  1. 开启DEBUG日志 进入canal_adapter/conf目录,编辑application.yml文件,添加如下内容

    logging:
      level:
        com.alibaba.otter.canal.client.adapter.es: DEBUG
    
  2. 重启 Canal Adapter:

    sh bin/stop.sh && sh bin/startup.sh
    

    结果 :自动同步立即恢复。

重启之后发现神奇的恢复了,后来想了想之前进行了哪些操作,编辑了ai_sys_scores.yml文件,然后我又编辑了该文件,未重启服务, 发现自动同步又失效了,立马重启之后,自动同步恢复正常了。添加日志操作解救了我啊,不然还想不到重启,一直尝试其他方法。

涉及的核心知识点

Canal 工作原理

  • canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送 dump 协议

  • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )

  • canal 解析 binary log 对象(原始为 byte 流)

  • Canal Server:

    • 伪装为 MySQL Slave,订阅 Binlog 事件。
    • 通过 instance.properties 定义监听规则(库表过滤、位点存储)。
  • Canal Adapter:

    • 作为 Canal Client,订阅 Server 的事件并转换为目标数据源(如 ES)的写入操作。
    • 依赖 destination 和 groupId 匹配 Server 的实例。

故障链分析

graph TD
  A[自动同步失效] --> B{手动ETL成功?}
  B -->|是| C[Binlog监听问题]
  C --> D[Canal Server未捕获事件]
  D --> E[过滤规则错误/权限不足]
  C --> F[Adapter未处理事件]
  F --> G[订阅关系失效/配置不匹配/修改配置未重启]
  G --> H[重启Adapter恢复]

常见陷阱

  1. 配置大小写敏感:

    • destination 和 groupId 必须与 Canal Server 完全一致。
  2. 热加载失效:

    • 修改 *.yml 后需重启 Adapter 或触发配置监控线程(部分版本需手动重启)。
  3. 静默失败:

    • ES 字段类型不匹配时,Adapter 可能丢弃数据且不报错。

4. 预防与优化建议

  1. 监控告警:

    • 监听 Canal Server 和 Adapter 的日志关键词(ERRORWARN)。
    • 定期校验 ES 索引数据与 MySQL 的一致性。
  2. 自动化运维:

    • 使用 Canal Admin 管理实例和监控客户端状态。
    • 配置 Adapter 定时重启(如每日低峰期)。

结语

看似简单的“重启大法”背后,实则是 订阅关系失效 和 运行时状态不一致 的深层问题。通过本次排查,不仅解决了问题,更梳理出 Canal 数据同步的核心链路和常见陷阱,希望对大家有帮助。

附录: