alibaba / canal Goto Github PK
View Code? Open in Web Editor NEW阿里巴巴 MySQL binlog 增量订阅&消费组件
License: Apache License 2.0
阿里巴巴 MySQL binlog 增量订阅&消费组件
License: Apache License 2.0
canal v1.0.2版本支持的MemoryEventStoreWithBuffer,是通过定义bufferSize来控制内存使用,但遇到大文本字段时,单纯按照记录数来控制就很容易爆内存.
所以,需要支持基于内存大小管理的EventStore,同时支持按内存大小获取数据,方便client进行内存控制.
MemoryEventStoreWithBuffer.setBufferMemSize()
问题: 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());
解决:
ddl语句会在Transaction Buffer中被缓存中,只有在下一次出现Transaction Begin/End的消息时,才会输出到store中,client才可见
解决:ddl语句在binlog协议中,前后不会有begin/commit事件,需要特殊处理,进入Transaction Buffer后,也立马flush到store中
影响版本 <= 1.0.3
canal driver module for otter ${project.version}
modulename 太长了
binlog_format模式有statement, row ,mixed三种模式,主要的区别在于insert/update/delete记录是否采取sql方式,还是详细的记录变更.
期望:
问题描述:
原因分析:
影响的版本 <= 1.0.3.
异常栈:
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");
}
}
1.0.0版本代码提交
mysql driver在处理返回的数据包没有考虑异常情况
在deployer工程里的canal.properties里的
canal.address=
是否应该改为
canal.ip=
因为在 CanalConstants 这个类里是如下定义的:
public static final String CANAL_IP = ROOT + "." + "ip";
问题:
集群模式下,客户端与instance断开连接,zookeeper running节点
自动被删除了。并且查看canal.log,无任何异常信息输出。
请问这是目前的bug么,还是说zookeeper配置问题 ?
我所期望的:
客户端断开链接后,running节点依然存在,下次客户端连接上来,可以继续使用之前的信息,包括cursor信息。
ps:貌似看到类似问题是1.0.3解决。现在是啥版本。。。
采用虚ip进行mysql主备管理时,暴露的ip只有1个,目前canal识别主备切换是根据ip和对应meta信息中的ip地址发生不一致时,进行一次切换操作,基于时间戳重新定位binlog .
所以,当使用虚ip,后端发生了主备切换,前端无法感知,一直会出现对应binlog不存在的错误,一直重试,从而导致canal整个不可用
解决:在出现binlog不存在的错误时,尝试按照时间戳重新定位binlog .
什么情况下binlog会出现不存在:
针对情况2,需要避免。解决办法:当按照时间戳进行重新定位binlog时,如果当前所有binlog的时间戳都晚于查找的时间戳,那应该挂起,不能直接使用第一个binlog进行解析处理
eclipse直接运行CanalLanuncher会启动失败,对应依赖的canal.properties和spring/xxx-instance.xml无法找到
原因:
解决:
默认配置中,canal选择的是file-intance.xml机制,会将相关数据定时刷新到文件. 而文件的存储默认是和instance的配置文件在一起.
比如 conf/example/meta.dat.
所以在scan定时扫描的时候,就会发现instance下的文件有所变化,导致需要进行一次reload.
解决: scan扫描时,忽略.dat的文件变更
client启动时需要做一个check :
支持mysql 5.6吗?
canal 主
canal 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 从
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
在LogEventConvert中处理时column,信息不正确。
扫描conf目录下的子目录,排除spring以外,将目录名做为instance destination,自动加载该instance,默认读取global lazy
支持多个mysql parse数据合并为一个store输出,进行消费。
典型的业务:数据按水平拆分为16个库后,合并为逻辑的一个canal destination进行消费,客户端不用关心后续16个库的链接情况
需要考虑:
需要新增AdminGuide,指导用户如何正确配置canal的相关参数,以及运维的基本操作
能不能增加手册 或者详细的文档?谢谢!
mysql packet介绍:模拟mysql登录,select/update语句与mysql进行通讯
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 table中字段类型为text时,数据库编码和表编码均为utf-8,canal配置的解析编码为utf-8,解析出来的数据记录为乱码.
原因分析:
解决:
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
增加testcase用例,引导别人使用
新增DevGuide,指导用户如何开发canal的组件,主要是介绍canal的类结构和模型
运行一段时间后,与mysql之间的数据库链接达到了几千条,且全部都是处于ESTABLISHED状态。
进行jmap dump内存对象,却无法找到SocketChannelImpl的相关实例,说明是被full gc回收了.
计划支持非zookeeper模式,也可以有持久化的功能,关闭canal server后,下一次启动时也能继续上一次的位置进行消费数据,不会丢失数据
注意: 基于file持久化的模式,存在一个问题,就是无法实现集群failover的功能,因为file属于本机,failover切换到另一机器后无法找到file,会造成无法找到上一次解析位置.
出错提示:
'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.
线上测试遇到一个问题:
a. 业务执行sql插入了一条记录,其中一个字段为:'210012\000\000\000'
b. otter中美同步,更新了这条记录,将字段更新为: '210012' (去除了\000)
c. canal再一次解析时,发现before和after值相同,没有任何字段发生变更,导致otter同步sql执行失败。
原因分析:
代码:
for (; (found < end) && buf[found] != '\0'; found++)
说明: \0为c-style风格的字符串结束符,至于业务执行怎么插入了\000,目前暂未知原因
canal server启动时针对canal.ip配置为空时,默认监听为AddressUtils.getHostIp()的地址,导致多IP地址不可访问.
解决:
canal deployer在打包的时候,将conf也打入到了jar中,而在一些特定的环境下,classloader会优先加载了jar包中的conf配置文件,从而导致在打包目录下的配置一直未生效.
也就是说:conf下和canal.deployer-xxxx.jar中都有canal.properties和instance.properties
解决办法:
v1.0.0的版本中,设定编码需要同时设置charsetNumber和connectionCharset,charsetNumber主要是和mysql进行handshark时,指定character_set_results的返回编码。connectionCharset指定为客户端的解析编码
每个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 1.0.2版本以及以前的版本,在设计的时候,canal server针对instance管理一直都是lazy模式处理. 当canal client断开链接时,canal server会主动关闭instance,等下一次canal client链接后再重新创建.
先前的考虑:
改进:
一个前提,客户端disconnect/connect间隔时间不会很长,尽可能减少资源消耗.
目前关注表的正则,可以通过两种方式进行设置
如果方式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 1.0.6版本之前,解析的schema , tablename 全部转化为了小写。
解决:需要保留下binlog中记录的内容,不做大小写转化
支持基于本地文件存储的EventStore实现,解决一对多的需求.
需要考虑的几个点:
Entry数据中isKey的数据返回错误,全部返回为true
canal server在重启后,没有重新读取一次客户端subscribe()提交的filter记录,导致启动时重新载入了instance.properties,client filter条件被丢弃
解决:canal instance重新启动时,优先读取一次MetaManager中记录的client filter信息
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)
问题说明:
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");
RT.
解决: CanalConnector新增方法
目前已知会导致挂起的ddl操作:
会导致信息错乱的ddl操作:
原因:
问题描述:
存在的问题: 就是在第三步出现异常后,没有更新对应的cache数据,导致下一次解析时一直使用上一次错误的tablemeta,导致一直出错,一直在重试.
问题: 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
;;
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.