在忍耐了好久以后,忍不住爆发了,在掘金发了条沸点(下班时发的):mysql
这是一个使人悲伤的故事,这条情感爆发的沸点好像被屏蔽了,另外小水渠(Canal
意为水道、管道)上线一段时间,不出坑的时候风平浪静,一旦出坑使人想屎。重点吐槽几点:git
RELEASE
版本为v1.1.4
,发布于2019-9-2
,快一年没更新了。Issue
里面堆积了十分多未处理或者没有回应的问题,有很多问题的年纪比较大。master
分支常常提交异常的代码,构建不友好,由于v1.1.4
比较多问题,也曾经想过用master
代码手动构建,导入项目以后决定放弃,谁试试谁知道,能够尝试对比导入和构建MyBatis
的源码。这些都只是表象,下面聊聊踩过的坑。github
这个基本是每一个使用Canal
的开发者的必踩之坑。$CANAL_HOME/conf/canal.properties
配置文件中存在一行注释掉的配置:canal.instance.parser.parallelThreadSize = 16
。该配置用于指定解析器实例并发线程数,若是注释了会致使解析线程阻塞,获得的结果就是什么都不会发生。sql
注释解除便可,建议使用默认值16
。shell
这是Issue
里面很大部分提问者提到可是久未解决的问题,也就是表结构元数据的存储问题(配置项里面使用了tsdb
也就是时序数据库的字眼,下面就称为tsdb
功能)。数据库
默认开启tsdb
功能,也就是会经过h2
数据库缓存解析的表结构,可是实际状况下,若是上游变动了表结构,h2
数据库对应的缓存是不会更新的,这个时候通常会出现神奇的解析异常,异常的信息通常以下:缓存
Caused by: com.alibaba.otter.canal.parse.exception.CanalParseException: column size is not match for table:数据库名称.表名称,新表结构的字段数量 vs 缓存表结构的字段数量;
该异常还会致使一个可怕的后果:解析线程被阻塞,也就是binlog
事件不会再接收和解析。这个问题笔者也查看过不少Issue
,你们都认为是一个严重的BUG
,目前认为比较可行的解决方案是:禁用tsdb
功能(真的够粗暴),也就是canal.instance.tsdb.enable
设置为false
。若是不由用tsdb
功能,一旦出现了该问题,必需要先中止Canal
服务,接着删除$CANAL_HOME/conf/目标数据库实例标识/h2.mv.db
文件,而后启动Canal
服务。服务器
由于这个比较坑的问题,笔者在生产禁用了tsdb
功能,而且添加了DDL
语句的处理逻辑,直接打到钉钉预警上而且@
整个群的人。架构
每次看到这个预警都心惊胆战。并发
若是恰好须要定位的binlog
位点处于比较靠后的文件,文件数量比较多,会疯狂打印寻位的日志。以前尝试太重启一会儿打印了几GB
日志,超过99%
是定位binlog
文件和position
的日志行。能够考虑经过修改$CANAL_HOME/conf/logback.xml
(并不建议,不清楚源码容易形成其余新的问题)配置或者指定$CANAL_HOME/conf/目标数据库实例标识/instance.properties
的下面几个属性手动定位解析的起点:
canal.instance.master.journal.name=binlog的文件名 canal.instance.master.position=binlog的文件中的位点 canal.instance.master.timestamp=时间戳 canal.instance.master.gtid=gtid的值
以上的手动定位解析的起点的属性须要在下次重启Canal以前更新或者注释掉,不然会形成从新解析或者找不到文件的严重后果!!!
反正每次重启Canal
服务都惊心动魄,没有一个开源软件可让人有这种感受。由于生产的服务器磁盘不是很充足,选配的时候只买了100GB
,并且考虑到这些日志本质上没有太大意义,因而只能按期上去删日志,前期是手动删,后来以为麻烦写了个Shell
脚本定时删除久远的日志文件。
若是恰好使用了阿里云的RDS MySQL
,那么有可能会遭遇更大的坑。主要问题是:
RDS MySQL
有磁盘空间优化规则,触发了规则会把binlog
文件上传到OSS
,而后删除本地的binlog
文件。Canal
的文档来看,会自动拉取OSS
上的binlog
文件进行解析,让使用者无感知,可是此功能有BUG
,一直没法正常使用。RDS MySQL
是一个暗箱,出了问题只能经过MySQL
的相关查询去定位问题,没有办法进去服务器查看真实的现场。命中了这个问题,通常出现的异常是:
.................. sqlstate = HY000 errmsg = Could not find first log file name in binary log index file
能够基本确认这个功能是存在缺陷的,例如这里有个Issue-2596:
目前笔者的作法以下:
Canal
拉取OSS
上的binlog
文件的功能。RDS MySQL
尽量扩容一下磁盘,调整策略让尽量多的binlog
文件尽量久地保留在本地,让它们被彻底解析后再手动上传或者命中了过时规则后自动上传,这期间有不少东西须要额外收取费用,具体须要自行权衡。读取和解析OSS上的binlog文件在目前(2020-08-05)的master分支上依然有BUG,想手动构建master分支的伙伴建议放弃幻想。
这个问题的严重后果是:有比较大的可能性致使某段binlog
文件解析彻底缺失,除非能够把binlog
文件从新塞回去RDS MySQL
里面,不然须要作上下游手动同步功能。
除此以外,要注意Canal
最好作主备部署,提交位点和集群管理建议使用Zookeeper
,而服务模式(canal.serverMode
,目前支持tcp
、kafka
和rocketmq
)建议选用Kafka
(master
分支上有RabbitMQ
的链接器支持,若是想尝鲜能够手动构建一下),而且每一个节点的资源要求比较高,笔者生产上每一个节点使用了2C8G
低主频的ECS
,感受有点压不住,特别时重启实例的时候若是须要从新定位binlog
位点,CPU
在一段时间内使用率会飙高。
笔者发现了阿里云的DTS
就是使用了Canal
做为基础中间件进行数据同步的,说明它有被投产到实际应用场景中,真不但愿它最终演变成废弃的KPI
任务项目。不知道日后还会遇到多少问题,若是碰到了也会持续更新本避坑指南。
(本文完 c-2-d e-a-20200805)
这是公众号《Throwable》发布的原创文章,收录于专辑《架构与实战》。