Canal是阿里开源产品之一,是用java开发的基于数据库增量日志解析,提供增量数据订阅&消费的中间件。目前,Canal主要支持了MySQL的binlog解析。
为何要解析binlog: binlog中含有许多我们需要的信息,基于这些信息,我们可以实现很多功能:
MySQL主从同步原理:
Canal模拟binlog用的传输协议,把自己伪装成slave,抓取日志:
目前最新的版本是Canal1.0.21,在这个版本修复了几个bug
这几个bug比较重要,所以最好用最新版的canal。之后的otter最新版的默认内置canal版本为1.0.20,最好在这里自己编译下并替换。
git clone .git
mvn clean install -st.skip -Denv=release
配置测试数据库,开启binlog:
log-bin=mysql-bin #添加这一行就ok
binlog-format=ROW #选择row模式,虽然Canal支持各种模式,但是想用otter,必须用ROW模式
server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复
添加Canal用户:
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
在编译好的目录下的target中找到canal.deployer-1.0.,解压
mkdir /usr/local/canal
tar zxvf canal.deployer-1.0. -C /usr/local/canal
配置conf/example/instance.properties:
#################################################
## mysql serverId
## 这个id不能和目标源数据库的id一样
sql.slaveId = 1234# 数据库地址,binlog订阅开始点
canal.instance.master.address = 10.202.4.39:3308
canal.instance.master.journal.name = mysql-binlog.000005
canal.instance.master.position = 126596922
canal.instance.master.timestamp = # 配置备用源数据库
#canal.instance.standby.address =
#canal.instance.standby.journal.name =
#canal.instance.standby.position =
#canal.instance.standby.timestamp = # username/password
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal
canal.instance.defaultDatabaseName =
tionCharset = UTF-8# 订阅哪些表的binlog,支持正则表达式
canal. = .*\..*
# 过滤掉的表的正则表达式
canal.instance. = #################################################
订阅起始点可自定义,查看当前binlog状态:
show master status;
一般的,binlog通过文件名和position就可以定位到,timestamp一般可以不用填。
配置conf/canal.properties:
#################################################
######### common argument #############
#################################################
canal.id= 1000001
canal.ip= 10.202.44.205
canal.port= 20999
# canal通过zk做负载均衡
canal.zkServers= 127.0.0.1:2181
# flush data to zk
keeper.flush.period = 1000
# flush meta cursor/parse position to file
canal.file.data.dir = ${f.dir}
canal.file.flush.period = 1000
## memory store RingBuffer size, should be Math.pow(2,n)
buffer.size = 16384
## memory store RingBuffer used memory unit size , default 1kb
unit = 1024
## meory store gets mode used MEMSIZE or ITEMSIZE
de = MEMSIZE## detecing config
canal.able = false
#canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()
canal.instance.detecting.sql = select 1
canal.instance.detecting.interval.time = 3
canal.threshold = 3
canal.instance.detecting.heartbeatHaEnable = false# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery
ansaction.size = 1024
# mysql fallback connected to new master should fallback times
canal.instance.fallbackIntervalInSeconds = 60# network config
iveBufferSize = 16384
canal.instancework.sendBufferSize = 16384
canal.instancework.soTimeout = 30# binlog filter config
canal.instance.filter.query.dcl = false
canal.instance.filter.query.dml = false
canal.instance.filter.query.ddl = false
canal.instance. = false# binlog format/image check
canal.instance.binlog.format = ROW,STATEMENT,MIXED
canal.instance.binlog.image = FULL,MINIMAL,NOBLOB# binlog ddl isolation
ddl.isolation = false#################################################
######### destinations #############
#################################################
canal.destinations= example
# conf root dir
f.dir = ../conf
# auto scan instance dir add/remove and start/stop instance
canal.auto.scan = true
canal.auto.scan.interval = 5canal.de = spring
canal.instance.global.lazy = false
#canal.instance.global.manager.address = 127.0.0.1:1099
#canal.instance.l = classpath:l
canal.instance.l = classpath:l
#canal.instance.l = classpath:l
剩下的配置我在Canal源代码分析中会细讲,敬请期待。
配置好,启动:
./bin/startup.sh
查看日志,启动成功。
之后利用客户端程序测试:
import java.InetSocketAddress;
import java.util.List;import canal.client.CanalConnector;
import canal.client.CanalConnectors;
import canalmon.utils.AddressUtils;
import canal.protocol.Message;
import canal.protocol.CanalEntry.Column;
import canal.protocol.CanalEntry.Entry;
import canal.protocol.CanalEntry.EntryType;
import canal.protocol.CanalEntry.EventType;
import canal.protocol.CanalEntry.RowChange;
import canal.protocol.CanalEntry.RowData;/*** Created by 862911 on 2016/3/8.*/
public class CanalClientUtil {public static void main(String args[]) {// 创建链接CanalConnector connector = wSingleConnector(new InetSocketAddress("10.202.44.205",20999), "example", "", "");int batchSize = 1000;int emptyCount = 0;try {t();connector.subscribe(".*\..*");llback();int totalEmtryCount = 120;while (emptyCount < totalEmtryCount) {Message message = WithoutAck(batchSize); // 获取指定数量的数据long batchId = Id();int size = Entries().size();if (batchId == -1 || size == 0) {emptyCount++;System.out.println("empty count : " + emptyCount);try {Thread.sleep(1000);} catch (InterruptedException e) {}} else {emptyCount = 0;// System.out.printf("message[batchId=%s,size=%s] n", batchId, size);Entries());}connector.ack(batchId); // 提交确认// llback(batchId); // 处理失败, 回滚数据}System.out.println("empty too many times, exit");} finally {connector.disconnect();}}private static void printEntry(List<Entry> entrys) {for (Entry entry : entrys) {if (EntryType() == EntryType.TRANSACTIONBEGIN || EntryType() == EntryType.TRANSACTIONEND) {continue;}RowChange rowChage = null;try {rowChage = RowChange.StoreValue());} catch (Exception e) {throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + String(),e);}EventType eventType = EventType();System.out.println(String.format("================> binlog[%s:%s] , name[%s,%s] , eventType : %s",Header().getLogfileName(), Header().getLogfileOffset(),Header().getSchemaName(), Header().getTableName(),eventType));for (RowData rowData : RowDatasList()) {if (eventType == EventType.DELETE) {BeforeColumnsList());} else if (eventType == EventType.INSERT) {AfterColumnsList());} else {System.out.println("-------> before");BeforeColumnsList());System.out.println("-------> after");AfterColumnsList());}}}}private static void printColumn(List<Column> columns) {for (Column column : columns) {System.out.Name() + " : " + Value() + " update=" + Updated());}}
}
测试结果:
================> binlog[mysql-binlog.000005:126600892] , name[express2,exp_data_waybill] , eventType : INSERT
waybill_no : 444502894553 update=true
delivery_tel : jHR4SS2qWgxxAntO1y1HVA== update=true
delivery_mobile : sKBkAB0Z3LGVCbVfS1YOZQ== update=true
delivery_contact : FdVG8RGFYwtWL9MU6QoMxg== update=true
delivery_addr : CW4QuCFWXlDZdTQCGgJLPe+LiC3hKPV7ykvdB7qx7dE= update=true
delivery_company : - update=true
delivery_addr_lat : 0.0 update=true
delivery_addr_lng : 0.0 update=true
consignee_tel : kcObfcMJkQ+uAh2RtAZ6cQ== update=true
consignee_mobile : b0mwnXp6/YKX/MKXX6S8CQ== update=true
consignee_contact : b0mwnXp6/YKX/MKXX6S8CQ== update=true
consignee_addr : XESDfeSycHu4VHDE/ns1QksFDEmfVhkUgGWZ/+ea+tpU4Dq+d1/Rez4RGvRdALOS update=true
consignee_company : sf-express update=true
source_zone_code : update=true
dest_zone_code : 010 update=true
meterage_weight_qty : 20.0 update=true
real_weight_qty : 1.0 update=true
quantity : 1.0 update=true
consignee_emp_code : 000212 update=true
consigned_tm : 2016-03-04 17:25:42 update=true
deliver_emp_code : update=true
subscriber_name : update=true
signin_tm : 0000-00-00 00:00:00 update=true
cargo_type_code : C201 update=true
limit_type_code : T4 update=true
distance_type_code : R10102 update=true
transport_type_code : TR2 update=true
express_type_code : B1 update=true
bill_long : update=true
bill_width : update=true
bill_high : update=true
volume : 120000.0 update=true
last_modified_tm : 2016-03-08 11:15:24 update=true
is_child_waybill : N update=true
is_deleted : 0 update=true
created_time : 2016-03-08 11:15:27 update=true
inputer_emp_code : BSP update=true
modified_time : 2016-03-08 11:15:27 update=true
================> binlog[mysql-binlog.000005:126601605] , name[express2,exp_data_waybill] , eventType : UPDATE
-------> before
waybill_no : 906501983434 update=false
delivery_tel : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
delivery_mobile : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
delivery_contact : +nSsYUguIjG7al33EaPDzA== update=false
delivery_addr : AfdjSlmWTbKQgeqVaQgDvw== update=false
delivery_company : 啊啊啊啊啊啊 update=false
delivery_addr_lat : 0.0 update=false
delivery_addr_lng : 0.0 update=false
consignee_tel : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
consignee_mobile : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
consignee_contact : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
consignee_addr : qoPgg0MX3wMoT1g9JpRQFA== update=false
consignee_company : soreufgd update=false
source_zone_code : update=false
dest_zone_code : 010A update=false
meterage_weight_qty : 100.0 update=false
real_weight_qty : 100.0 update=false
quantity : 1.0 update=false
consignee_emp_code : 002776 update=false
consigned_tm : 2016-03-01 10:45:00 update=false
deliver_emp_code : update=false
subscriber_name : update=false
signin_tm : 0000-00-00 00:00:00 update=false
cargo_type_code : C201 update=false
limit_type_code : T4 update=false
distance_type_code : R10102 update=false
transport_type_code : TR2 update=false
express_type_code : B1 update=false
bill_long : update=false
bill_width : update=false
bill_high : update=false
volume : update=false
last_modified_tm : 2016-03-01 14:22:09 update=false
is_child_waybill : N update=false
is_deleted : 0 update=false
created_time : 2016-03-04 19:59:20 update=false
inputer_emp_code : 000000 update=false
modified_time : 2016-03-04 19:59:20 update=false
-------> after
waybill_no : 906501983434 update=false
delivery_tel : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
delivery_mobile : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
delivery_contact : +nSsYUguIjG7al33EaPDzA== update=false
delivery_addr : AfdjSlmWTbKQgeqVaQgDvw== update=false
delivery_company : 啊啊啊啊啊啊 update=false
delivery_addr_lat : 0.0 update=false
delivery_addr_lng : 0.0 update=false
consignee_tel : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
consignee_mobile : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
consignee_contact : 9BxLJQjsg8u0y5T4Prf0Hg== update=false
consignee_addr : qoPgg0MX3wMoT1g9JpRQFA== update=false
consignee_company : soreufgd update=false
source_zone_code : update=false
dest_zone_code : 010A update=false
meterage_weight_qty : 100.0 update=false
real_weight_qty : 100.0 update=false
quantity : 1.0 update=false
consignee_emp_code : 002776 update=false
consigned_tm : 2016-03-01 10:45:00 update=false
deliver_emp_code : update=false
subscriber_name : update=false
signin_tm : 0000-00-00 00:00:00 update=false
cargo_type_code : C201 update=false
limit_type_code : T4 update=false
distance_type_code : R10102 update=false
transport_type_code : TR2 update=false
express_type_code : B1 update=false
bill_long : update=false
bill_width : update=false
bill_high : update=false
volume : update=false
last_modified_tm : 2016-03-08 11:18:25 update=true
is_child_waybill : N update=false
is_deleted : 0 update=false
created_time : 2016-03-04 19:59:20 update=false
inputer_emp_code : 000000 update=false
modified_time : 2016-03-08 11:18:27 update=true
可以看出,基于ROW格式的binlog解析,我们可以解析出是何种语句,以及每条记录是怎么更新的。
本文发布于:2024-02-04 18:17:17,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170713476258193.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |