一、异常现象截图
二、解决方式:
1、背景
早期的canal版本(<=1.0.24),在处理表结构的DDL变更时采用了一种简单的策略,在内存里维护了一个当前数据库内表结构的镜像(通过desc table获取)。
这样的内存表结构镜像的维护存在问题,如果当前在处理的binlog为历史时间段T0,当前时间为T1,存在的一些异常分支情况:
补充一下MySQL binlog的一些技术背景:
本文作者:张永清,转载请注明出处:https://www.cnblogs.com/laoqing/p/13187324.html
ps. 针对复杂的一条update中包含多张表的更新时,大家可以观察一下Table_map的特殊情况,留待有兴趣的同学发挥
2、方案
扯了一堆的背景之后,再来看一下我们如何解决canal上一版本存在的表结构一致性的问题,这里会把我们的思考过程都记录出来,方便大家辩证的看一下方案.
解决这个问题,第一个最直接的思考:canal在订阅binlog时,尽可能保持准实时,不做延迟回溯消费. 这样的方式会有对应的优点和缺点:
整个方案上,基本是想避开表结构的问题,在遇到一些容灾场景下一定也会遇上,不是一个技术解决的方案,废弃.
经过了第一轮辩证的思考,基本确定想通过迂回的方式,简单绕过一致性的问题不是正解,所以这次的思考主要就是如何正面解决一致性的问题. 基本思路:基于binlog中DDL的变化,来动态维护一份表结构,比如DDL中增加一个列,在本地表结构中也动态增加一列,解析binlog时都从本地表结构中获取
实现方案:
整个方案上,可以绝大部分的解决DDL的问题,但也存在一些缺点:
有了之前的两次思考,思路基本明确了,在一次偶然的机会中和alibaba Druid的作者高铁,交流中得到了一些灵感,是否可以基于Druid对DDL的支持能力,来构建一份动态的表结构.
大致思路:
接口设计:
public interface TableMetaTSDB { /** * 初始化 */ public boolean init(String destination); /** * 获取当前的表结构 */ public TableMeta find(String schema, String table); /** * 添加ddl到时间表结构库中 */ public boolean apply(BinlogPosition position, String schema, String ddl, String extra); /** * 回滚到指定位点的表结构 */ public boolean rollback(BinlogPosition position); /** * 生成快照内容 */ public Map<String/* schema */, String> snapshot(); }
持久化存储的思考:
canal.instance.tsdb.spring.xml=classpath:spring/tsdb/h2-tsdb.xml
#canal.instance.tsdb.spring.xml=classpath:spring/tsdb/mysql-tsdb.xml
参数名 | 默认值 | 描述 |
---|---|---|
canal.instance.tsdb.enable | true | 是否开启时序表结构的能力 |
canal.instance.tsdb.dir | ${canal.file.data.dir:../conf}/${canal.instance.destination:} | 默认存储到conf/$instance |
canal.instance.tsdb.url | jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL; | jdbc链接串 |
canal.instance.tsdb.dbUsername | canal | jdbc用户名,因为有自动创建表的能力,所以对该用户需要有create table的权限 |
canal.instance.tsdb.dbPassword | canal | jdbc密码 |
例子:
# table meta tsdb info
canal.instance.tsdb.enable=true
canal.instance.tsdb.dir=${canal.file.data.dir:../conf}/${canal.instance.destination:}
canal.instance.tsdb.url=jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;
#canal.instance.tsdb.url=jdbc:mysql://127.0.0.1:3306/canal_tsdb
canal.instance.tsdb.dbUsername=canal
canal.instance.tsdb.dbPassword=canal
目前canal 1.0.26最新版已经默认开启了时序表结构的能力,just have fun !
原文:https://www.cnblogs.com/laoqing/p/13187324.html