1.CanalServer 配置(当前介绍使用 ZK注册的方式)
材料:canal 服务器部署包 canal.deployer-1.0.24.tar.gz
(https://pan.baidu.com/s/1uujF_kvSYArTaJRAGS3PVQ)
配置: conf 目录下的 canal.properties
懒人使用法(配置能用就可以,好吧,一点也不专业。):
①服务器节点的ID(随便设置一个)
②port 监听端口,随便。
③zkServers,zk集群逗号隔开即可。
①destinations,节点读取目录,在conf目录下创建一个目录,这边创建的节点名字为vads0
②默认配置是file-instance.xml 这个就是各种信息会使用文件的形式记录,我选择使用这边写的default-instance.xml ,因为我不想去看文件。default有一行配置将游标记录在ZK服务上面。
区别就是cursor文件有没有在ZK上面记录。
①在刚刚创建的目录vads0 下面创建文件 instance.properties
②slaveId 随便写
③address mysql服务器url 比如 127.0.01:3306
后面三个是指定日志解析的节点,不填的话 第一次启动默认就是在当前时间节点开始解析binarylog日志。(后续启动都会读取cursor继续解析binarylog)
(cursor里面就是这个: {"@type":“com.alibaba.otter.canal.protocol.position.LogPosition”,“identity”:{“slaveId”:-1,“sourceAddress”:{“address”:“127.0.0.1”,“port”:3306}},“postion”:{“included”:false,“journalName”:“mysql-bin.000006”,“position”:166609270,“serverId”:1,“timestamp”:1525661348000}})
④用户名,密码,defaultDatabaseName(这个填了不代表这个服务器下别的database不会被解析 一样会被解析的)
⑤过滤正则(白名单,黑名单)
#################################################
## mysql serverId
canal.instance.mysql.slaveId = 1234
# position info
canal.instance.master.address =
canal.instance.master.journal.name =
canal.instance.master.position =
canal.instance.master.timestamp =
# username/password
canal.instance.dbUsername =
canal.instance.dbPassword =
canal.instance.defaultDatabaseName =
canal.instance.connectionCharset = UTF-8
# table regex
canal.instance.filter.regex = .\…
# table black regex
canal.instance.filter.black.regex =
#################################################
2.CanalClient
注意点:一个server 就一个client连接的上去。(不肯定,我这边是这样。)
依赖
<dependency>
<groupId>com.alibaba.otter</groupId>
<artifactId>canal.client</artifactId>
<version>1.0.24</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
</exclusions>
</dependency>
连接
//zkServers节点名字,instanceName 上面配置的目录名字 后面两个是用户名密码 不用配置
CanalConnector canalConnector = CanalConnectors.newClusterConnector(zkServers, instanceName, null, null);
//连接
canalConnector.connect();
//订阅
canalConnector.subscribe();
//连接可用就一直请求数据
while(canalConnector.checkValid()){
// 未确认的获取数据 超时,数据量随便设置
try {
Message msg = canalConnector.getWithoutAck(messageBatchSize, messageTimeout, TimeUnit.MILLISECONDS);
if (msg == null || msg.getEntries().isEmpty()) {
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
log.error("Thread error {}", e);
}
return;
}
batchId = msg.getId();
if (batchId <= 0) {
return;
}
//todo msg就是实际的事件 msg怎么解析请参考附件。msg 是 entry的集合 (一个entry就是一个ddl 或者dml (没有查询)), entry 有header 跟rowchange。 细节有点多,写不清楚,所以还是看代码来的实际一点。
//解析完成的确认(这样就会推到下一个节点继续解析)
canalConnector.ack(batchId);
} catch (Exception e) {
if (batchId > 0) {
try {
canalConnector.rollback(batchId);
} catch (Exception ex) {
log.error("##Canal rollback error!");
throw new Exception("##Canal rollback error!");
}
}
log.error("##Canal consumer error.");
}
}
canalConnector.unsubscribe();
canalConnector.disConnect();