canal学习2–canal Adapter使用
canal Adapter使用
背景
开发过程中,数据同步到es中,一般都需要代码来ETL数据,然后同步到es中。这是应为在es中的index一般都是很多表的一些数据集合而成,并不是单纯的一张表就能解决的。
如果es的表变动只需要单表时,其实可以考虑canalAdapter的来配置就可以了,无须代码。
准备
本地运行的win10环境。[ ]中为当前使用的版本
canal.deployer [1.1.5]
canal.adapter [1.1.5]
rabbitMQ
mysql [8x]
jdk [1.8.0_91]
canalDeployer安装使用
具体参考 canal学习1–canal初始安装使用 即可,这里就不复述了。
本次用例需要在 conf目录下新增个instance的配置: bz_goods
conf
|-- bz_goods
|-- instance.properties
## instance.properties配置如下。其余的默认值处理
# mysql的主链接地址
canal.instance.master.address=127.0.0.1:3306
# mysql的主链接账号密码
canal.instance.dbUsername=canal
canal.instance.dbPassword=canal123
canal.instance.connectionCharset = UTF-8
canalAdapter安装使用
canal.adapter主要是数据做ETL处理。可以通过配置各种适配器来扩展。
这个图比较抽象的表示核心的功能点。当然,canal.adapter中内部也做了很多处理,比如并发处理等等来提升性能。具体建议参考源码。
结构说明
canal.adapter中存在以下几个文件夹:
- bin:存放着startup.sh、startup.bat、stop.sh
- conf:存在核心的配置信息
1. application.yml 存放启动器的配置属性
2. bootstrap.yml 配置信息如果想存放到数据库中管理时,可以配置存放的数据库连接。有变动的时候,能延长3s左右做到变动更新。
3. logback.xml 日志配置
4. es6/es7/hbase/kudu/rdb 存放的是各个对应消费类型的适配器文件。 - lib:运行依赖的jar库
- logs:默认的存放log日志的
- plugin:用于存放各种适配器的jar地址。使用SPI方式被canal.adapter所引用。
启动器
以mysql的bz_goods.supplier库表变动,同步到 data_collector.supplier_etl为例。
application.yml配置
#### 项目对外暴露的restApi端口号
server:
port: 8081
#### json处理的相关配置
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
#### canal的核心配置
canal.conf:
# 数据来源适配的类型
mode: tcp #tcp kafka rocketMQ rabbitMQ
# 扁平message开关, 是否以json字符串形式投递数据, 仅在kafka/rocketMQ模式下有效
flatMessage: true
# canal.adapter集群zk的配置
zookeeperHosts:
# 设置每次批量大小,把数据传给数据消费适配器处理
syncBatchSize: 1000
# 用于获取数据时,异常时处理,重试次数。-1时表示一致阻塞(其实就是设值为 Integer.MAX)。
retries: 0
# 用于获取数据时。等待数据的时长。单位毫秒。(默认 500L)
timeout:
# aliyun ak/sk
accessKey:
secretKey:
### 数据来源
consumerProperties:
# canal的TCP数据消费方式
canal.tcp.server.host: 127.0.0.1:11111
canal.tcp.zookeeper.hosts:
canal.tcp.batch.size: 500
canal.tcp.username:
canal.tcp.password:
# kafka 数据消费
kafka.bootstrap.servers: 127.0.0.1:9092
kafka.enable.auto.commit: false
kafka.auto.commit.interval.ms: 1000
kafka.auto.offset.reset: latest
kafka.request.timeout.ms: 40000
kafka.session.timeout.ms: 30000
kafka.isolation.level: read_committed
kafka.max.poll.records: 1000
# rocketMQ 数据消费
rocketmq.namespace:
rocketmq.namesrv.addr: 127.0.0.1:9876
rocketmq.batch.size: 1000
rocketmq.enable.message.trace: false
rocketmq.customized.trace.topic:
rocketmq.access.channel:
rocketmq.subscribe.filter:
# rabbitMQ 数据消费
rabbitmq.host:
rabbitmq.virtual.host:
rabbitmq.username:
rabbitmq.password:
rabbitmq.resource.ownerId:
### 数据来源的 数据源配置,支持配置多个。主要是在操作restApi进行同步时用于查询来源数据使用的。
srcDataSources:
DS_bz_goods:
url: jdbc:mysql://127.0.0.1:3306/bz_goods?useUnicode=true
username: client
password: client123
DS_bz_order:
url: jdbc:mysql://127.0.0.1:3306/bz_order?useUnicode=true
username: client
password: client123
### 数据去处时适配器配置。可以配置多个,并发执行。每个适配器都有个对应的instance。
canalAdapters:
# 对应canal destination 或者 topic
- instance: bz_goods
# 消费组,可以配置多个。组之间是 并行
groups:
# 消费组其一的ID
- groupId: group_01
# 消费者 group_01 下的多个数据去处 适配器。
# 组内的适配器是串行处理。如果其中一个异常,会导致下面的的适配器不能执行。
outerAdapters:
# 适配器类型。即目前支持的通过SPI加载的适配器。从 plugin文件夹中读取的。
- name: rdb
# 适配器key。具体适配器yml中配置 outerAdapterKey引用。
key: toMysql
properties:
jdbc.driverClassName: com.mysql.jdbc.Driver
jdbc.url: jdbc:mysql://127.0.0.1:3306/data_collector?useUnicode=true
jdbc.username: client
jdbc.password: client123
# - instance: example # canal instance Name or mq topic name
# groups:
# - groupId: g1
# outerAdapters:
# - name: logger
# - name: rdb
# key: mysql1
# properties:
# jdbc.driverClassName: com.mysql.jdbc.Driver
# jdbc.url: jdbc:mysql://127.0.0.1:3306/mytest2?useUnicode=true
# jdbc.username: root
# jdbc.password: 121212
# - name: rdb
# key: oracle1
# properties:
# jdbc.driverClassName: oracle.jdbc.OracleDriver
# jdbc.url: jdbc:oracle:thin:@localhost:49161:XE
# jdbc.username: mytest
# jdbc.password: m121212
# - name: rdb
# key: postgres1
# properties:
# jdbc.driverClassName: org.postgresql.Driver
# jdbc.url: jdbc:postgresql://localhost:5432/postgres
# jdbc.username: postgres
# jdbc.password: 121212
# threads: 1
# commitSize: 3000
# - name: hbase
# properties:
# hbase.zookeeper.quorum: 127.0.0.1
# hbase.zookeeper.property.clientPort: 2181
# zookeeper.znode.parent: /hbase
# - name: es
# hosts: 127.0.0.1:9300 # 127.0.0.1:9200 for rest mode
# properties:
# mode: transport # or rest
# # security.auth: test:123456 # only used for rest mode
# cluster.name: elasticsearch
# - name: kudu
# key: kudu
# properties:
# kudu.master.address: 127.0.0.1 # ',' split multi address
适配器配置
以rdb同步mysql的为例:
rdb/bz_goods.supplier.yml
# dataSourceKey 在binlog数据同步时用不到。但是在人工restApi时必须要有
dataSourceKey: DS_bz_goods
#表示对应的 application.yml中的 instance
destination: bz_goods
#对应哪个outerAdapter的消费组
groupId: group_01
#对应消费组中的哪个outAdapter
outerAdapterKey: toMysql
# 是否并行同步
concurrent: true
dbMapping:
# 源数据源的database/shcema
database: bz_goods
# 源数据源表名
table: supplier
# 目标数据源的库名
targetDb: data_collector
# 目标数据源的表名
# 并不能按照之前的文档格式:库名.表名 这里应该就是表面,库名使用targetDb指定,或者默认使用对应outerAdapter中的表示的库名
targetTable: supplier_etl #supplier
targetPk:
id: id
# 是否整表映射, 要求源表和目标表字段名一模一样 (如果targetColumns也配置了映射,则以targetColumns配置为准)
# 注意 这段表述“以targetColumns配置为准”。这个并不是说只同步 targetColumns配置的属性。而是说一样要同步 源表的所有属性。
# 但是考虑到目标表的属性名称可能不完全一致,有区别的属性名称可以通过targetColumns来配置映射关系,没有配置的默认属性默认都是相同。
# 如果只需要同步部分源表的属性到目标表中,这里应该设置false
mapAll: false
# 字段映射, 格式: 目标表字段: 源表字段, 如果字段名一样源表字段名可不填
# 注意数据源的 to: from 前面是数据要同步到的地方,后面是数据来源的
targetColumns:
id: id
abbr_name_01: abbr_name
full_name_01: full_name
contact_person_01: contact_person
# 参数占位符格式: {} 请求参数时按照顺序 etlCondition只用于 restApi中的etl请求使用。不会参与binlog数据同步中
etlCondition: "where id > {} and bdy_supplier_id = {}"
# 用于ETL中,每次commit时,一批批量提交的大小
commitBatch: 3000
## Mirror schema synchronize config
#dataSourceKey: defaultDS
#destination: example
#groupId: g1
#outerAdapterKey: mysql1
#concurrent: true
#dbMapping:
# mirrorDb: true
# database: mytest
代码idea中执行
前面执行start.bat时,各种问题。没有办法,只好看源码去研究。这里也写下使用idea运行canal.adapter时的注意点。
代码结构
client-adapter
|-- pom.xml
|-- common 封装的是公共模块
|-- es6x ES6x对应的适配器代码
|-- resources
|-- es6
|-- xxx.yml 某个具体索引与来源数据的映射配置
|-- META-INFO.canal
|-- com.alibaba.otter.canal.client.adapter.OuterAdapter SPI方式加载es适配器实现
|-- es7x ES7x对应的适配器代码
|-- resources
|-- es7
|-- xxx.yml 某个具体索引与来源数据的映射配置
|-- META-INFO.canal
|-- com.alibaba.otter.canal.client.adapter.OuterAdapter SPI方式加载es适配器实现
|-- escore ES核心模块,比如config、adapter实现等
|-- hbase hbase对应的适配器
|-- resources
|-- hbase
|-- xxx.yml 某个具体hbase与来源数据的映射配置
|-- META-INFO.canal
|-- com.alibaba.otter.canal.client.adapter.OuterAdapter SPI方式加载es适配器实现
|-- kudu kudu分布式数据库适配器
|-- resources
|-- kudu
|-- xxx.yml 某个具体kudu库表与来源数据的映射配置
|-- META-INFO.canal
|-- com.alibaba.otter.canal.client.adapter.OuterAdapter SPI方式加载es适配器实现
|-- logger 日志的适配器
|-- resources
|-- META-INFO.canal
|-- com.alibaba.otter.canal.client.adapter.OuterAdapter SPI方式加载es适配器实现
|-- rdb 关系型数据库适配器
|-- resources
|-- rdb
|-- xxx.yml 某个具体rdb库表与来源数据的映射配置
|-- META-INFO.canal
|-- com.alibaba.otter.canal.client.adapter.OuterAdapter SPI方式加载es适配器实现
|-- launcher 主程序,adapter启动运行的核心
|-- main
|-- assembly 存放编辑时配置
|-- ${evn}.xml 不同环境时的编辑配置
|-- bin 脚本命令
|-- restart.sh linux下重新启动
|-- startup.bat win下启动
|-- startup.sh linux下启动
|-- stop.sh linux下停止
|-- java 实现代码
|-- resources 资源文件
|-- META-INFO
|-- spring.factories spring提供的SPI机制,它读取META-INF/spring.factories文件中配置的接口实现类名称,然后在程序中读取这些配置文件并实例化。
|-- application.yml 启动配置文件
|-- bootstrap.yml springboot启动加载,记载优先application.yml。常用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性
|-- logback.xml 日志配置
canal.adapter中也是需要 connector组件的。connector的组件结构大致与adapter的类似。
代码运行
在canal.adapter运行前,必须先启动canal.deployer
项目导入idea中之后,一定要运行下canal client adapter module for otter 1.1.5
下的install执行。会把相关使用的jar放到指定的路径下面,这样launcher
组件才能启动成功。不然就会报错:
程序包 xxxxx 不存在
运行时直接启动 CanalAdapterApplication.main(xxx)
方法启动即可。
然后在 bz_goods.supplier进行操作时,能看到相关的数据会同时同步到data_collectore.supplier中。
同步RestApi操作
- 查询所有订阅同步的canal destination或MQ topic
GET http://localhost:8081/destinations
#结果
[
{
"destination": "bz_goods",
"status": "on"
},
{
"destination": "example",
"status": "on"
}
]
- 查看相关库总数据。格式:
/count/{type}/{task}
GET http://localhost:8081/count/rdb/toMysql/bz_goods.supplier.yml
#结果
{
"count": 1,
"targetTable": "`data_collector`.`supplier_etl`"
}
- 手动ETL。格式:
/etl/{type}/{key}/{task}
POST http://localhost:8081/etl/rdb/toMysql/bz_goods.supplier.yml?params=12;9993
Content-Type: application/x-www-form-urlencoded
- 获取实例开关状态。格式:
/syncSwitch/{destination}
GET http://localhost:8081/syncSwitch/bz_goods
#结果
{
"stauts": "on"
}
- 实例开关控制。格式:
/syncSwitch/{destination}/{status} 开关状态: off on
PUT http://localhost:8081/syncSwitch/bz_goods/off
#结果
{
"code": 20000,
"message": "实例: bz_goods 关闭同步成功"
}