云计算百科
云计算领域专业知识百科平台

Canal GTID 位点失效解决方案

Canal GTID 位点失效解决方案

文档背景:生产 Canal 实例因主库 binlog 被清理(purge),导致持久化位点失效、无法继续订阅,持续报错 errno 1236。本文完整记录该问题的现象、根因、排查思路与解决方案。本次生产故障已通过「删实例 + 重建」方案成功恢复。

脱敏说明:本文为脱敏版本,涉及环境地址、域名、IP、账号密码、实例名、binlog 文件名、位点、GTID 串等敏感信息均已替换为占位符(<…>),结构与操作命令完整保留,可直接套用到其他环境。


1. 问题现象

Canal 实例启动后反复重试,destination 一直处于异常状态,无法正常消费 binlog。实例日志(logs/<实例名>/<实例名>.log)持续输出以下两类错误:

错误一:GTID 模式(开启 GTID 时)

ERROR c.a.o.canal.parse.inbound.mysql.dbsync.DirectLogFetcher – I/O error while reading from client socket
java.io.IOException: Received error packet: errno = 1236, sqlstate = HY000
errmsg = The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1,
but the master has purged binary logs containing GTIDs that the slave requires.

关键日志(启动时找到的旧位点):

prepare to find start position just last position
{"postion":{"gtid":"<GTID串>",
"journalName":"<binlog文件名>","position":<position>,"timestamp":<时间戳>}}

错误二:关闭 GTID 后(file+position 模式)

java.io.IOException: Received error packet: errno = 1236, sqlstate = HY000
errmsg = Could not find first log file name in binary log index file

即 Canal 拿着旧的 binlog 文件名(<binlog文件名>)+ position 去 dump,但主库的 binlog 索引文件里已经没有这个文件了。


2. 根因分析

层面原因
直接原因 Canal 持久化的消费位点(cursor)指向的 binlog 已被主库清理(purge),无法继续 dump
深层原因 消费端长期停止 / Canal 故障停机 / 消费延迟过大,期间主库按保留策略清理了 binlog;Canal 恢复后拿着旧位点去拉,主库校验失败
GTID 模式下的表现 MySQL 开启 MASTER_AUTO_POSITION=1 后,会校验从机(即 Canal)提交的 GTID 集合,如果集合中包含已被 purge 的事务,直接拒绝并返回 1236
非 GTID 模式下的表现 直接用 journalName+position 定位,binlog 文件不存在时返回 1236「Could not find first log file name」

核心结论:该问题不是连接问题、也不是配置语法问题,而是位点过期。binlog 已被清理的历史增量无法找回,只能让 Canal 丢弃旧位点、从主库当前最新位点重新订阅。


3. 排查思路(如何定位是不是位点失效)

3.1 确认 MySQL 连接正常

报错出现前先排除连接问题:

# 在 Canal Server 机器上测试到主库的连通性
telnet <源MySQL主机> 3306

或确认实例配置中 canal.instance.master.address 正确。若连接正常、报错集中在 dump 阶段(errno 1236),即为位点问题。

3.2 判断 GTID 与 binlog 是否被清理

在主库执行:

— 当前 binlog 文件列表
SHOW BINARY LOGS;
— 或 MySQL 8.0+
SHOW MASTER STATUS;

— binlog 保留策略
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW VARIABLES LIKE 'expire_logs_days';

若错误日志中的 journalName(如 <binlog文件名>)已不在 SHOW BINARY LOGS 列表中,确认 binlog 已被清理,即位点失效。

3.3 定位 Canal 的位点存哪(重要,决定清法)

Canal 的位点(cursor)持久化位置取决于部署模式:

部署模式位点存储位置
普通模式(conf/ 本地实例) 本地文件 conf/<实例名>/meta.dat
admin manager 模式(有 conf/spring/、canal_local.properties) 独立持久化在 admin 侧(Web 操作或 admin 数据库)

admin manager 模式的判定:

cat /opt/canal/server/conf/canal_local.properties
# 出现 canal.admin.manager = <admin地址>:8089 即为 admin 模式

本地 meta.dat 排查(admin 模式下本地 conf/ 只有 example 实例,其它实例无本地 meta.dat):

find /opt/canal/server -name "meta.dat"

3.4 查看实例当前配置内容

  • admin 模式:登录 admin Web(http://<canal-admin域名>:8089,默认账号 admin/<默认密码>)→「实例管理」→「修改」查看配置内容。
  • 重点检查:
    • canal.instance.master.journal.name / master.position / master.gtid / master.timestamp 是否带旧值
    • canal.instance.gtidon 是否为 false

4. 解决方案

方案一:admin Web 修改配置清空位点(优先尝试)

适用于 admin manager 模式。1.1.5 的 Web 操作菜单只有「修改 / 删除 / 启动 / 停止 / 日志」,没有「重置位点」按钮,只能手动清配置。

  • 登录 admin Web → 「实例管理」→ 找到故障实例 → 「修改」。
  • 将以下配置项的值全部清空(等号后留空),并确认 gtidon 关闭:
  • canal.instance.gtidon = false
    canal.instance.master.gtid =
    canal.instance.master.timestamp =
    canal.instance.master.journal.name =
    canal.instance.master.position =

  • 「保存」→ 实例列表「停止」→ 等 5 秒 → 「启动」。
  • 查看实例日志确认恢复。
  • 注意事项:若配置已按上述清空,但实例日志仍显示旧位点(prepare to find start position just last position + 旧 journalName/gtid),说明 cursor 独立持久化、不随配置修改清除,此方案无法解决,请直接采用方案二或方案三。

    方案二:删除实例 + 重建(本次实际采用,已验证成功)

    位点 cursor 绑定实例,删除实例可连带清除;前提是已备份配置内容。本次生产故障即通过该方案成功恢复。

  • 「实例管理」→ 故障实例 → 「操作」→「删除」。
  • 「新建 Instance」:名称、所属集群、所属主机、配置内容与原来一致(确保第 4.1 节中 5 个位点配置项为空)。
  • 保存 → 「启动」→ 查看日志。
  • 方案三:直接清 admin 数据库中的持久化 cursor(Web 无法解决时)

    适用场景:配置已清空,但日志仍显示旧位点(说明 cursor 独立持久化,Web 改不到)。

  • 在任意有 mysql 客户端的机器连 admin 库:
  • mysql -h <admin数据库主机> -P 3306 -u <账号> -p <库名>

  • 定位 cursor 所在表(全库搜旧 GTID 或旧 binlog 文件名):
  • SHOW TABLES;

    SELECT * FROM <表名> WHERE <字段> LIKE '%<旧gtid前20位>%'\\G
    SELECT * FROM <表名> WHERE <字段> LIKE '%<旧binlog文件名>%'\\G

  • 备份后清空:
  • UPDATE <表名> SET <字段> = REPLACE(<字段>, '<旧binlog文件名>', ''), modified_time = NOW() WHERE name = '<实例名>';
    — 旧 position / gtid 值同理

  • 重启实例验证。

  • 5. 关键原理:为什么必须「同时」清 timestamp 和 cursor

    Canal 启动时找起始位点的优先级:持久化 cursor(last position)优先于配置中的位点项。

    清了什么Canal 启动用的起点结果
    都不清 旧 cursor(旧 binlog 文件 + position + 旧 GTID) 报错(初始状态)
    只清 cursor 配置中的 master.timestamp(可能更早的过期时间点) 仍报错(该时间点的 binlog 也可能已 purge)
    只清 timestamp 旧 cursor 仍报错
    两者都清 主库当前最新 binlog 正常恢复

    因此即使配置里 journal.name/position/gtid 已清空,若 master.timestamp 还带着旧时间戳、或存在独立持久化的 cursor,问题不会消失。

    代价说明:清位点会跳过被 purge 的那段历史增量(本来也已无法找回),从当前时刻起正常订阅新数据。


    6. 预防与根治建议

    措施说明
    增大 binlog 保留时间 主库设置 binlog_expire_logs_seconds = 604800(7 天)或更长,确保 Canal 停机/延迟期间 binlog 不被清理
    监控 Canal 消费延迟 消费位点滞后超过阈值(如 binlog 保留期的 50%)触发告警
    消费端及时 ACK 确认下游消费正常,避免位点堆积
    不要随意删 meta.dat / 清位点 正常情况清位点 = 丢增量,仅在本问题(已无法找回)时使用
    升级 Canal 版本 新版 admin 提供更完善的位置管理能力,可评估升级

    7. 附录

    7.1 本文实例环境(脱敏)

    项目说明
    Canal 版本 1.1.5(deployer + admin)
    部署模式 admin manager 管理(canal.admin.manager = <admin地址>:8089)
    admin Web http://<canal-admin域名>:8089(默认账号 admin/<默认密码>)
    admin 数据库 <admin数据库主机>:3306,库名 <库名>
    故障实例 <实例名>(源库 <源MySQL主机>:3306)
    故障位点 journalName=<binlog文件名>, position=<position>

    7.2 关键日志定位词速查

    # 实例日志
    tail -f logs/<实例名>/<实例名>.log

    # 重点关键字
    grep -E "errno = 1236|purged binary logs|Could not find first log file|find start position" logs/<实例名>/<实例名>.log

    7.3 相关链接

    • Canal 官方文档:https://github.com/alibaba/canal
    • 本文配套文档:[Canal 升级 jar 包操作文档-FastJSON示例.md]
    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Canal GTID 位点失效解决方案
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!