Giter Site home page Giter Site logo

alibaba / canal Goto Github PK

View Code? Open in Web Editor NEW
28.1K 1.2K 7.5K 22.5 MB

阿里巴巴 MySQL binlog 增量订阅&消费组件

License: Apache License 2.0

Java 94.65% Shell 1.13% Batchfile 0.11% Dockerfile 0.19% Python 0.05% HTML 0.15% CSS 0.01% JavaScript 1.32% Vue 2.00% PLpgSQL 0.21% SCSS 0.19%

canal's Issues

canal MemoryStore支持按内存大小定义

canal v1.0.2版本支持的MemoryEventStoreWithBuffer,是通过定义bufferSize来控制内存使用,但遇到大文本字段时,单纯按照记录数来控制就很容易爆内存.

所以,需要支持基于内存大小管理的EventStore,同时支持按内存大小获取数据,方便client进行内存控制.

MemoryEventStoreWithBuffer.setBufferMemSize()

mysql YEAR类型binlog输出使用short替换Date

问题: mysql YEAR类型在canal1.0.3版本中使用了java.sql.Date对象来标示,无法准确的表示一个年份信息,原本一个年份2013,输出结果会是:2013-01-01

if (cal == null)
cal = Calendar.getInstance();
cal.clear();
cal.set(Calendar.YEAR, i32 + 1900);
value = new java.sql.Date(cal.getTimeInMillis());

解决:

  1. 直接使用数字存储表示,protobuf输出结果为2013

DDL语句不能及时输出

ddl语句会在Transaction Buffer中被缓存中,只有在下一次出现Transaction Begin/End的消息时,才会输出到store中,client才可见

解决:ddl语句在binlog协议中,前后不会有begin/commit事件,需要特殊处理,进入Transaction Buffer后,也立马flush到store中

影响版本 <= 1.0.3

支持binlog_format为statement,mixed模式的解析输出

binlog_format模式有statement, row ,mixed三种模式,主要的区别在于insert/update/delete记录是否采取sql方式,还是详细的记录变更.

期望:

  1. canal也可以支持非row模式的数据解析,解析对应的sql. (非row模式下,不会提供before/after columns信息)

client基于zookeeper地址断开一次后,立马重新启动,偶儿会出现NPE异常

问题描述:

  1. client基于zookeeper地址获取canal server的工作节点
  2. client第一次起来工作后,被非正常退出,比如kill. 然后立马又重新启动
  3. client会出现NullPointException异常

原因分析:

  1. client第一次启动后,会在zookeeper记录一个client running节点,非正常退出后,running节点不会立马小时
  2. 当client下一次立马启动后,发现running节点存在,并不会立马创建socket,当执行后面的get数据操作时,发现socket为null,就出现了NPE问题

影响的版本 <= 1.0.3.

windows在与mysql建立链接时,出现unexpected blocking io behavior异常

异常栈:

0:42:02.725 [main] WARN c.a.o.c.p.d.mysql.MysqlConnector - connect failed!java.io.IOException: unexpected blocking io behavior
at com.alibaba.otter.canal.parse.driver.mysql.utils.PacketManager.write(PacketManager.java:54)
at com.alibaba.otter.canal.parse.driver.mysql.MysqlConnector.negotiate(MysqlConnector.java:159)
at com.alibaba.otter.canal.parse.driver.mysql.MysqlConnector.connect(MysqlConnector.java:66)
at com.alibaba.otter.canal.parse.driver.mysql.MysqlConnectorTest.testQuery(MysqlConnectorTest.java:20)

对应代码:

public static void write(SocketChannel ch, ByteBuffer[] srcs) throws IOException {
long total = 0;
for (ByteBuffer buffer : srcs) {
total += buffer.remaining();
System.out.println(total);
}
long size = ch.write(srcs);
if (size != total) {
throw new IOException("unexpected blocking io behavior");
}
}

集群模式下,客户端与instance断开连接,zookeeper running节点 自动被删除了

问题:
集群模式下,客户端与instance断开连接,zookeeper running节点
自动被删除了。并且查看canal.log,无任何异常信息输出。
请问这是目前的bug么,还是说zookeeper配置问题 ?

我所期望的:
客户端断开链接后,running节点依然存在,下次客户端连接上来,可以继续使用之前的信息,包括cursor信息。

ps:貌似看到类似问题是1.0.3解决。现在是啥版本。。。

mysql主备切换采用虚ip切换,canal的failover机制

采用虚ip进行mysql主备管理时,暴露的ip只有1个,目前canal识别主备切换是根据ip和对应meta信息中的ip地址发生不一致时,进行一次切换操作,基于时间戳重新定位binlog .
所以,当使用虚ip,后端发生了主备切换,前端无法感知,一直会出现对应binlog不存在的错误,一直重试,从而导致canal整个不可用

解决:在出现binlog不存在的错误时,尝试按照时间戳重新定位binlog .

什么情况下binlog会出现不存在:

  1. 虚ip mysql主备切换
  2. canal解析延迟过久,对应binlog已经被删除.

针对情况2,需要避免。解决办法:当按照时间戳进行重新定位binlog时,如果当前所有binlog的时间戳都晚于查找的时间戳,那应该挂起,不能直接使用第一个binlog进行解析处理

eclipse中直接启动canal server

eclipse直接运行CanalLanuncher会启动失败,对应依赖的canal.properties和spring/xxx-instance.xml无法找到

原因:

  1. canal server启动时为了简化路径依赖,都使用了相对路径或者classpath:进行描述资源依赖,所以基于eclipse启动后,导致查找资源失败

解决:

  1. 将conf/目录下的配置,加入到eclipse的classpath中

scan定时扫描需要忽略canal meta/paser.dat文件

默认配置中,canal选择的是file-intance.xml机制,会将相关数据定时刷新到文件. 而文件的存储默认是和instance的配置文件在一起.

比如 conf/example/meta.dat.

所以在scan定时扫描的时候,就会发现instance下的文件有所变化,导致需要进行一次reload.

解决: scan扫描时,忽略.dat的文件变更

HA模式下mysql master-standby无法自动切换

canal 主

canal config

detecing config

canal.instance.detecting.enable = true
canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()
canal.instance.detecting.interval.time = 3
canal.instance.detecting.retry.threshold = 3
canal.instance.detecting.heartbeatHaEnable = true

example log

2013-05-14 10:23:29.509 [destination = example , address = /192.168.196.82:3306 , EventParser] WARN c.alibaba.otter.canal.parse.driver.mysql.MysqlConnector - connect failed!java.net.ConnectException: Connection refused
at sun.nio.ch.Net.connect(Native Method)
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:525)
at com.alibaba.otter.canal.parse.driver.mysql.MysqlConnector.connect(MysqlConnector.java:65)
at com.alibaba.otter.canal.parse.inbound.mysql.MysqlConnection.connect(MysqlConnection.java:51)
at com.alibaba.otter.canal.parse.inbound.AbstractEventParser$3.run(AbstractEventParser.java:141)
at java.lang.Thread.run(Thread.java:679)

canal 从

detecing config

canal.instance.detecting.enable = true
canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()
canal.instance.detecting.interval.time = 3
canal.instance.detecting.retry.threshold = 3
canal.instance.detecting.heartbeatHaEnable = true

column字段变更信息丢失

在LogEventConvert中处理时column,信息不正确。

  1. isUpdate所有都为true,正确的应该是:根据before和after字进行判断.
  2. sqlType所有都为0,正确应该是:int类型对应于的java.sql.Types

instance增加自动扫描机制

扫描conf目录下的子目录,排除spring以外,将目录名做为instance destination,自动加载该instance,默认读取global lazy

mysql instance支持group模式

支持多个mysql parse数据合并为一个store输出,进行消费。
典型的业务:数据按水平拆分为16个库后,合并为逻辑的一个canal destination进行消费,客户端不用关心后续16个库的链接情况

需要考虑:

  1. 强一致 (group内所有的parse都正常工作,才运行客户端消费数据)
  2. 弱一致 (group内只要有一个parse正常工作,就允许客户端消费数据)

canal新增AdminGuide

需要新增AdminGuide,指导用户如何正确配置canal的相关参数,以及运维的基本操作

[feature request]MySQL table encoding automatic identification

schema编码识别:
SELECT default_character_set_name FROM information_schema.SCHEMATA S
WHERE schema_name = "schemaname";

表编码识别:
SELECT CCSA.character_set_name FROM information_schema.TABLES T,
information_schema.COLLATION_CHARACTER_SET_APPLICABILITY CCSA
WHERE CCSA.collation_name = T.table_collation
AND T.table_schema = "schemaname"
AND T.table_name = "tablename";

字段编码识别:
SELECT character_set_name FROM information_schema.COLUMNS C
WHERE table_schema = "schemaname"
AND table_name = "tablename"
AND column_name = "columnname";

mysql text中文字符出现乱码

mysql table中字段类型为text时,数据库编码和表编码均为utf-8,canal配置的解析编码为utf-8,解析出来的数据记录为乱码.

原因分析:

  1. mysql binlog中将text/blob类型都记录为LogEvent.MYSQL_TYPE_BLOB
  2. canal识别到BLOB信息,无法区分是text还是blob,都按照iso-8859-1进行编码,导致问题的产生

解决:

  1. 拿到binlog后,针对BLOB类型,需要反查下table meta信息,获取真实的字段类型,区分出text,然后按照编码进行解析.

canal server running节点判断是否为本机操作优化

canal server在zookeeper的节点:

[zk: localhost:2181(CONNECTED) 15] get /otter/canal/destinations/example/running  
{"active":true,"address":"10.20.144.51:11111","cid":1}

目前一台机器,判断当前是否为工作节点,是通过cid是否和本机的id相同来判断,但目前cid这信息在启动canal server没有严格校验是否有重复,导致两台机器都认为是自己本机,对于后续的命令控制操作有风险

解决:将判断是否本机的操作,修改为基于address是否相同来判断,ip+port可以唯一定义一个jvm

canal新增DevGuide

新增DevGuide,指导用户如何开发canal的组件,主要是介绍canal的类结构和模型

mysql metaConnection链接泄漏

运行一段时间后,与mysql之间的数据库链接达到了几千条,且全部都是处于ESTABLISHED状态。

进行jmap dump内存对象,却无法找到SocketChannelImpl的相关实例,说明是被full gc回收了.

canal新增基于file记录位点信息,不依赖zookeeper持久化canal server状态

计划支持非zookeeper模式,也可以有持久化的功能,关闭canal server后,下一次启动时也能继续上一次的位置进行消费数据,不会丢失数据

注意: 基于file持久化的模式,存在一个问题,就是无法实现集群failover的功能,因为file属于本机,failover切换到另一机器后无法找到file,会造成无法找到上一次解析位置.

windows bat脚本启动失败

出错提示:

'conf_dir' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
'canal_conf' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
'logback_configurationFile' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
Listening for transport dt_socket at address: 9099
Exception in thread "main" java.lang.NoClassDefFoundError: com/alibaba/otter/can
al/deployer/CanalLauncher
Caused by: java.lang.ClassNotFoundException: com.alibaba.otter.canal.deployer.Ca
nalLauncher
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: com.alibaba.otter.canal.deployer.CanalLauncher.
Program will exit.

mysql varchar类型处理'\000'字符问题

线上测试遇到一个问题:
a. 业务执行sql插入了一条记录,其中一个字段为:'210012\000\000\000'
b. otter中美同步,更新了这条记录,将字段更新为: '210012' (去除了\000)
c. canal再一次解析时,发现before和after值相同,没有任何字段发生变更,导致otter同步sql执行失败。

原因分析:

  1. dbsync在解析'210012\000\000\000',等价于'210012',自动忽略了'\000'请求

代码:
for (; (found < end) && buf[found] != '\0'; found++)

说明: \0为c-style风格的字符串结束符,至于业务执行怎么插入了\000,目前暂未知原因

canal server启动时针对canal.ip配置为空时,默认监听为AddressUtils.getHostIp()的地址,导致多IP地址不可访问

canal server启动时针对canal.ip配置为空时,默认监听为AddressUtils.getHostIp()的地址,导致多IP地址不可访问.

解决:

  1. 如果配置ip地址为空时,默认socket的监听为 :${canal.port},不指定ip绑定,接收任何该机器任何ip过来的请求.
  2. 同时会通过AddressUtils.getHostIp()选择一个ip,暴露到zk中,由客户端进行访问.

canal server在windows下启动失败,conf目录下修改配置一直不生效

canal deployer在打包的时候,将conf也打入到了jar中,而在一些特定的环境下,classloader会优先加载了jar包中的conf配置文件,从而导致在打包目录下的配置一直未生效.

也就是说:conf下和canal.deployer-xxxx.jar中都有canal.properties和instance.properties

解决办法:

  1. 在canal.deployer-xxx.jar打包时去除conf目录.

canal HA模式cluster集群列表数据更新问题

每个instance下面都会有个cluster目录,代表服务这个instance的canal server的机器列表:

[zk: localhost:2181(CONNECTED) 15] ls /otter/canal/destinations/example/cluster 
[10.20.144.22:11111]

1.0.2版本的cluster列表只会在running节点抢占成功后才会生成running节点,和原本cluseter的定位想矛盾

解决: canal server启动对应的instance时,不管有没有抢占到running节点,都应该创建cluster节点,表明自己是可以work for this instance,如果此时发生running节点删除,客户端就可以从cluster列表中找到一个节点,进行链接,lazy的方式促使它进行启动。 (ps. 当然running节点删除,canal server的另一台机器自己也能感应到,并启动instance)

canal server在处理客户端主动关闭连接时,是否需要关闭instance

在canal 1.0.2版本以及以前的版本,在设计的时候,canal server针对instance管理一直都是lazy模式处理. 当canal client断开链接时,canal server会主动关闭instance,等下一次canal client链接后再重新创建.

先前的考虑:

  1. canal server主动关闭instance,主要是考虑是想将canal server作成无状态,下一次canal client可以随机选择一台机器获取数据,新的canal server会重新启动instance,整个HA模型会比较简单.

改进:

  1. canal server在client退出时不主动关闭instance资源
  2. 下一次canal client重新链接后,需要通过Cluster模式(通过zookeeper获取到HA模式中正在运行的canal server的机器信息),然后与其重新建立链接即可

一个前提,客户端disconnect/connect间隔时间不会很长,尽可能减少资源消耗.

关注表的条件变更,对应生效时间问题

目前关注表的正则,可以通过两种方式进行设置

  1. conf下的instance.properties中,可以设置table.regex,在第一次启动的时候直接载入使用
  2. 某个client进行subscribe(filter),可以提交一个filter

如果方式2中,提交了filter,目前的策略是直接覆盖了方式1中的条件,如果canal server选择了file/zookeeper持久化了meta,即使下次server重启,对应的关注表条件也会是方式2提交的数据

生效时间问题:
方式1:修改instance.properties,需要重启instance(如果开启scan,自动会重启),instance重启会回退一部分binlog,比如客户端未ack的数据,或者消费了一半的事务,还有就是未及时刷出内存位点数据到持久化介质. 所以,对应的生效时间会对之前的部分数据进行作用

方式2:关闭client,修改订阅条件后,会是同步即时生效,subscribe调用成功后,直接替换了canal server中老版本的filter.

canal中输出表名全为小写

canal 1.0.6版本之前,解析的schema , tablename 全部转化为了小写。

解决:需要保留下binlog中记录的内容,不做大小写转化

[feature request]Canal supports local file persist for EventStore

支持基于本地文件存储的EventStore实现,解决一对多的需求.

需要考虑的几个点:

  1. 文件数据的清理模型: 定时清理,ack清理,满清理
  2. 位点管理: binlog解析位点,文件位点
  3. 位点定位: 时间戳,binlog位置,文件位点
  4. 快慢队列: memory + file的混合模式支持,(定时将file数据读入到memory buffer中,提升效率)

canal自动重连时会出现destination:idbbond-1 should start first信息

2013-06-05 18:08:40.960 [main] INFO c.alibaba.otter.canal.client.impl.ClusterCanalConnector - restart the connector for next round retry.
2013-06-05 18:08:40.975 [main] WARN c.alibaba.otter.canal.client.impl.ClusterCanalConnector - something goes wrong when getWithoutAck data from server:/192.168.1.134:11111
com.alibaba.otter.canal.protocol.exception.CanalClientException: something goes wrong with reason: something goes wrong with channel:[id: 0x3622e177, /192.168.1.134:50993 => /192.168.1.134:11111], exception=com.alibaba.otter.canal.server.exception.CanalServerException: destination:idbbond-1 should start first

at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.getWithoutAck(SimpleCanalConnector.java:241)
at com.alibaba.otter.canal.client.impl.ClusterCanalConnector.getWithoutAck(ClusterCanalConnector.java:135)
at SimpleCanalClientExample.main(SimpleCanalClientExample.java:35)

问题说明:

  1. canal server在启动时,是先暴露了端口,再启动对应需要启动的instance,因为启动instance需要一点时间,所以有一定概率会撞上instance未启动完成.

mysql地址配置出错,增加异常描述信息

Caused by: org.springframework.beans.factory.BeanCreationException: Error creatng bean with name 'com.alibaba.otter.canal.parse.support.AuthenticationInfo#1f5ea4a' defined in class path resource [spring/file-instance.xml]: Initialization of bean failed; nested exception is java.lang.ArrayIndexOutOfBoundsException: 1
at org.springframework.beans.factory.support.AbstractAutowireCapableBeaFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480) ~[spring-2.5..jar:2.5.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeaFactory$1.run(AbstractAutowireCapableBeanFactory.java:409) ~[spring-2.5.6.jar:25.6]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.6._17]

解决:
识别出异常配置,抛异常时记录原始的配置信息.

throw new RuntimeException("address[" + text + "] is illegal, eg.127.0.0.1:3306");

mysql特定的ddl操作(删除字段,rename table等),导致解析挂起

目前已知会导致挂起的ddl操作:

  1. 字段删除
  2. rename table (导致desc table时找不到对应的meta信息,无法补全Entry信息)

会导致信息错乱的ddl操作:

  1. 首先删除一个字段,然后再新加一个字段(非添加到末尾)

原因:

  • mysql binlog中的tablemap LogEvent,没有包含对应的column name信息,只是按照当前table中column的顺序,列出了字段类型
  • 回退到ddl操作前的binlog重新开始解析,此时数据库中desc table所获取的信息就会和table map中不一致(无法进行match操作),会导致信息混乱

canal解析DDL操作出现异常,导致整个解析挂起

问题描述:

  1. 启动canal server/client
  2. 执行ddl操作,比如create,alter , delete,create表的操作. 特定的case触发DDL表名解析错误
  3. canal在解析binlog后,发现binlog column信息和当前tablemeta cache中的数据不一致,抛出异常,进行重试.

存在的问题: 就是在第三步出现异常后,没有更新对应的cache数据,导致下一次解析时一直使用上一次错误的tablemeta,导致一直出错,一直在重试.

mac下startup.sh启动脚本报错

问题: bin_abs_path=$(readlink -f $(dirname $0))
mac下readlink -f不能正常工作

解决:
case "uname" in
Linux)
bin_abs_path=$(readlink -f $(dirname $0))
;;
*)
bin_abs_path=cd $(dirname $0); pwd
;;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.