Bootstrap

超详细的canal使用总结

超详细的canal使用总结

canal的介绍

​ canal,译意为水道/管道/沟渠,从官网的介绍中可以知道,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费

​ 这是一张官网提供的示意图:

在这里插入图片描述

官网的解释最权威,我就直接引用一下官网的原话,另,附上官网地址:https://github.com/alibaba/canal

基于日志增量订阅和消费的业务包括

  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务 cache 刷新
  • 带业务逻辑的增量数据处理

MySQL主备复制原理

img

  • MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
  • MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
  • MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据

canal 工作原理

  • canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
  • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
  • canal 解析 binary log 对象(原始为 byte 流)

canal的部署

目标

​ 利用canal实现mysql->kafka场景。

环境准备

​ 在开始之前,我们要先准备好利用canal实现mysql->kafka场景所需要的环境,包括安装mysql,kafka,zookeeper。官方想得还是很周到的,专门提供了安装方式。

  1. zookeeper安装方式链接:https://github.com/alibaba/canal/wiki/Zookeeper-QuickStart
  2. kafka安装方式链接:https://github.com/alibaba/canal/wiki/Kafka-QuickStart
  3. mysql的安装方式不知道是不是我眼花,没在官网上找到,所以自己找了篇文章:https://www.cnblogs.com/wangpeng00700/p/13539856.html

​ 当然光是这些还不够,因为canal是基于mysql增量日志解析来实现的同步,mysql必须要先开启 Binlog 写入功能,配置 binlog-format 为 ROW 模式。如果之前已经安装了mysql,不清楚是否开启了的,可以通过以下命令查看。如果为ON,就表示已经开启了。我这里为了方便直接用Navicat进行查看了。

show variables like '%log_bin%'

在这里插入图片描述

​ 如果没有,那么需要调整一下/etc/my.cnf ,my.cnf 中配置如下。

[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复

​ 授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限, 如果已有账户可直接 grant。但是我为了方便,下面的例子是直接用的root用户,不建议学我。

-- 创建canal的用户
CREATE USER canal IDENTIFIED BY 'canal';  
-- 进行授权
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;

下载安装包

​ 本次例子以1.1.5版本为例,首先从官网上下载canal.deployer-1.1.5.tar.gz和canal.admin-1.1.5.tar.gz两个包,canal.admin-1.1.5.tar.gz是canal的核心之一,canal-admin设计上是为canal提供整体配置管理、节点运维等面向运维的功能,提供相对友好的WebUI操作界面,方便更多用户快速和安全的操作。canal有两种使用方式:1、独立部署 2、内嵌到应用中。 而deployer模块主要用于独立部署canal server,这次的例子采用独立部署的方式。

​ 安装包官网下载地址:https://github.com/alibaba/canal/releases

在这里插入图片描述

​ 安装包下载完成后,将它分别解压到系统对应的目录下,例如:/opt/lxf/canal,因为这次除了admin外还有deployer,所以还需在/opt/lxf/canal目录下再分别建admin和deployer两个目录。找到安装包,分别使用tar zxvf canal.admin-1.1.5.tar.gz -C /opt/lxf/canal/admin和tar zxvf canal.deployer-1.1.5.tar.gz -C /opt/lxf/canal/deployer命令将其解压到对应的目录下。

​ admin解压后可以看到4个文件夹:bin、conf、lib、logs。

​ deployer解压后可以看到5个文件夹:bin、conf、lib、logs、plugin。

配置admin

​ 先进入到admin下面的conf中,找到application.yml,通过vi编辑器修改里面的内容。

server:
  port: 8089 # 配置端口
spring:
  jackson: 
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

spring.datasource:
  address: 192.168.1.121:3306 # 配置数据库ip和端口
  database: canal_manager # 配置数据库名
  username: root # 配置登录用户
  password: 123456 # 配置登录密码
  driver-class-name: com.mysql.jdbc.Driver # 配置驱动
  url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false
  hikari:
    maximum-pool-size: 30
    minimum-idle: 1

# 配置链接canal-server的admin用户账号和密码
canal:
  adminUser: admin 
  adminPasswd: admin

​ 然后同样在conf目录下,可以找一个canal_manager.sql文件,这里面是canal需要执行的SQL脚本,它可以帮助我们初始化数据库。使用命令:mysql -h主机地址 -u用户名 -p用户密码,可连接mysql数据库。连接上之后再使用source命令执行canal_manager.sql文件。例如:

# 连接mysql数据库
mysql -h 127.0.0.1 -u root -p 123456

# 导入初始化SQL
source /opt/lxf/canal/admin/conf/canal_manager.sql

​ 如果linux上不方便操作,也可以将canal_manager.sql文件拷贝到windows系统里,用数据库管理工具(例如:Navicat)执行SQL脚本。

在这里插入图片描述

​ 执行了SQL脚本后,可以看到数据库里已经完成了初始化。

在这里插入图片描述

​ 当确认无误后,进入到admin下的bin目录,执行命令./startup.sh,通过脚本启动。这个时候admin已经启动起来了,如果想要停止的话,可执行./stop.sh

注意:执行前,需要先安装jdk,因为canal是基于java实现的。可自己去官网下载tar.gz包进行安装,或者系统版本是CentOS、Fedora或RedHat这样支持yum的,可执行安装命令:yum install -y java-1.8.0-openjdk-devel.x86_64。安装完成后,输入java -version验证,如下图表示安装成功。

在这里插入图片描述

配置deployer

​ 先进入deployer下的conf目录下,找到canal.properties文件,使用vi编辑器修改。

#################################################
######### 		common argument		#############
#################################################
# tcp bind ip
# canal server绑定的本地IP信息,如果不配置,默认选择一个本机IP进行启动服务
canal.ip =
# register ip to zookeeper
# canal server注册到外部zookeeper、admin的ip信息 (针对docker的外部可见ip)
canal.register.ip =
# canal server提供socket服务的端口
canal.port = 11111
canal.metrics.pull.port = 11112
# canal instance user/passwd
# canal.user = canal
# canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458

# canal admin config
#canal.admin.manager = 127.0.0.1:8089
# admin管理指令链接端口
canal.admin.port = 11110
# admin管理指令链接的ACL配置,用户名
canal.admin.user = admin
# admin管理指令链接的ACL配置,这个密码是admin,这是密码加密后的字符串
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
# admin auto register
#canal.admin.register.auto = true
#canal.admin.register.cluster =
#canal.admin.register.name =

# canal server链接zookeeper集群的链接信息,有多个时以,隔开
canal.zkServers =
# flush data to zk
# canal持久化数据到zookeeper上的更新频率,单位毫秒
canal.zookeeper.flush.period = 1000
canal.withoutNetty = false
# server模式,可选项,包含tcp, kafka, rocketMQ, rabbitMQ
canal.serverMode = tcp
# flush meta cursor/parse position to file
canal.file.data.dir = ${canal.conf.dir}
canal.file.flush.period = 1000
## memory store RingBuffer size, should be Math.pow(2,n)
# canal内存store中可缓存buffer记录数,需要为2的指数
canal.instance.memory.buffer.size = 16384
## memory store RingBuffer used memory unit size , default 1kb
# 内存记录的单位大小,默认1KB,和buffer.size组合决定最终的内存使用大小
canal.instance.memory.buffer.memunit = 1024 
## meory store gets mode used MEMSIZE or ITEMSIZE
# canal内存store中数据缓存模式
# 1. ITEMSIZE : 根据buffer.size进行限制,只限制记录的数量
# 2. MEMSIZE : 根据buffer.size  * buffer.memunit的大小,限制缓存记录的大小
canal.instance.memory.batch.mode = MEMSIZE
canal.instance.memory.rawEntry = true

## detecing config
# 是否开启心跳检查
canal.instance.detecting.enable = false
#canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()
# 心跳检查sql,与上面的开启联合使用
canal.instance.detecting.sql = select 1
# 心跳检查频率,单位秒
canal.instance.detecting.interval.time = 3
# 心跳检查失败重试次数
canal.instance.detecting.retry.threshold = 3
# 心跳检查失败后,是否开启自动mysql自动切换
# 说明:比如心跳检查失败超过阀值后,如果该配置为true,canal就会自动链到mysql备库获取binlog数据
canal.instance.detecting.heartbeatHaEnable = false

# support maximum transaction size, more than the size of the transaction will be cut into multiple transactions delivery
canal.instance.transaction.size =  1024
# mysql fallback connected to new master should fallback times
# canal发生mysql切换时,在新的mysql库上查找binlog时需要往前查找的时间,单位秒
# 说明:mysql主备库可能存在解析延迟或者时钟不统一,需要回退一段时间,保证数据不丢
canal.instance.fallbackIntervalInSeconds = 60

# network config
# 网络链接参数,SocketOptions.SO_RCVBUF
canal.instance.network.receiveBufferSize = 16384
# 网络链接参数,SocketOptions.SO_SNDBUF
canal.instance.network.sendBufferSize = 16384
# 网络链接参数,SocketOptions.SO_TIMEOUT
canal.instance.network.soTimeout = 30

# binlog filter config
# 是否使用druid处理所有的ddl解析来获取库和表名
canal.instance.filter.druid.ddl = true
# 是否忽略dcl语句
canal.instance.filter.query.dcl = false
# 是否忽略dml语句
canal.instance.filter.query.dml = false
# 是否忽略ddl语句
canal.instance.filter.query.ddl = false
# 是否忽略binlog表结构获取失败的异常(主要解决回溯binlog时,对应表已被删除或者表结构和binlog不一致的情况)
canal.instance.filter.table.error = false
# 是否dml的数据变更事件(主要针对用户只订阅ddl/dcl的操作)
canal.instance.filter.rows = false
# 是否忽略事务头和尾,比如针对写入kakfa的消息时,不需要写入
canal.instance.filter.transaction.entry = false
# 是否忽略插入
canal.instance.filter.dml.insert = false
# 是否忽略修改
canal.instance.filter.dml.update = false
# 是否忽略删除
canal.instance.filter.dml.delete = false

# binlog format/image check
# 支持的binlog format格式列表
canal.instance.binlog.format = ROW,STATEMENT,MIXED 
# 支持的binlog image格式列表
canal.instance.binlog.image = FULL,MINIMAL,NOBLOB

# binlog ddl isolation
# ddl语句是否单独一个batch返回(比如下游dml/ddl如果做batch内无序并发处理,会导致结构不一致)
canal.instance.get.ddl.isolation = false

# parallel parser config
# 是否开启binlog并行解析模式(串行解析资源占用少,但性能有瓶颈, 并行解析可以提升近2.5倍+)
canal.instance.parser.parallel = true
## concurrent thread number, default 60% available processors, suggest not to exceed Runtime.getRuntime().availableProcessors()
#canal.instance.parser.parallelThreadSize = 16
## disruptor ringbuffer size, must be power of 2
# binlog并行解析的异步ringbuffer队列(必须为2的指数)
canal.instance.parser.parallelBufferSize = 256

# table meta tsdb info
# 是否开启tablemeta的tsdb能力
canal.instance.tsdb.enable = true
# 主要针对h2-tsdb.xml时对应h2文件的存放目录,默认为conf/xx/h2.mv.db
canal.instance.tsdb.dir = ${canal.file.data.dir:../conf}/${canal.instance.destination:}
# jdbc url的配置
canal.instance.tsdb.url = jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;
# jdbc username的配置
canal.instance.tsdb.dbUsername = canal
# jdbc password的配置
canal.instance.tsdb.dbPassword = canal
# dump snapshot interval, default 24 hour
# 转储快照间隔时间,默认24小时
canal.instance.tsdb.snapshot.interval = 24
# purge snapshot expire , default 360 hour(15 days)
# 清除快照过期时间,默认15天
canal.instance.tsdb.snapshot.expire = 360

#################################################
######### 		destinations		#############
#################################################
# 当前server上部署的instance列表
canal.destinations = example
# conf root dir
# conf/目录所在的路径
canal.conf.dir = ../conf
# auto scan instance dir add/remove and start/stop instance
# 开启instance自动扫描
canal.auto.scan = true
# instance自动扫描的间隔时间,单位秒
canal.auto.scan.interval = 5
# set this value to 'true' means that when binlog pos not found, skip to latest.
# WARN: pls keep 'false' in production env, or if you know what you want.
canal.auto.reset.latest.pos.mode = false

# 全局的tsdb配置方式的组件文件
canal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml
#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml

# 全局配置加载方式
canal.instance.global.mode = spring
# 全局lazy模式
canal.instance.global.lazy = false
# 全局的manager配置方式的链接信息
canal.instance.global.manager.address = ${canal.admin.manager}
#canal.instance.global.spring.xml = classpath:spring/memory-instance.xml
# 全局的spring配置方式的组件文件
canal.instance.global.spring.xml = classpath:spring/file-instance.xml
#canal.instance.global.spring.xml = classpath:spring/default-instance.xml

### 以下为MQ的相关配置,配置具体含义根据对应的MQ解释,下面以kafka为例说明

##################################################
######### 	      MQ Properties      #############
##################################################
# aliyun ak/sk , support rds/mq
canal.aliyun.accessKey =
canal.aliyun.secretKey =
canal.aliyun.uid=

# 是否为json格式 如果设置为false,对应MQ收到的消息为protobuf格式,需要通过CanalMessageDeserializer进行解码
canal.mq.flatMessage = true
canal.mq.canalBatchSize = 50
canal.mq.canalGetTimeout = 100
# Set this value to "cloud", if you want open message trace feature in aliyun.
canal.mq.accessChannel = local

canal.mq.database.hash = true
canal.mq.send.thread.size = 30
canal.mq.build.thread.size = 8

##################################################
######### 		     Kafka 		     #############
##################################################
# 配置单个或多个kafka访问地址(支持集群)
kafka.bootstrap.servers = 127.0.0.1:9092
# kafka中的acks参数
kafka.acks = all
# kafka服务端指定压缩算法的参数compression.type
kafka.compression.type = none
# kafka批处理大小
kafka.batch.size = 16384
# 延时
kafka.linger.ms = 1
# kafka最大请求量
kafka.max.request.size = 1048576
# 内存缓冲的大小
kafka.buffer.memory = 33554432
# kafka重试机制中的max.in.flight.requests.per.connection参数
kafka.max.in.flight.requests.per.connection = 1
kafka.retries = 0

# 是否开启kafka的kerberos认证
kafka.kerberos.enable = false
kafka.kerberos.krb5.file = "../conf/kerberos/krb5.conf"
kafka.kerberos.jaas.file = "../conf/kerberos/jaas.conf"

##################################################
######### 		    RocketMQ	     #############
##################################################
rocketmq.producer.group = test
rocketmq.enable.message.trace = false
rocketmq.customized.trace.topic =
rocketmq.namespace =
rocketmq.namesrv.addr = 127.0.0.1:9876
rocketmq.retry.times.when.send.failed = 0
rocketmq.vip.channel.enabled = false
rocketmq.tag = 

##################################################
######### 		    RabbitMQ	     #############
##################################################
rabbitmq.host =
rabbitmq.virtual.host =
rabbitmq.exchange =
rabbitmq.username =
rabbitmq.password =
rabbitmq.deliveryMode =

​ 因为我们的目标是实现mysql->kafka场景,只需调整部分配置即可,以下是我自己的配置。

#################################################
######### 		common argument		#############
#################################################
# tcp bind ip
canal.ip =
# register ip to zookeeper
canal.register.ip =
canal.port = 11111
canal.metrics.pull.port = 11112
# canal instance user/passwd
# canal.user = canal
# canal.passwd = E3619321C1A937C46A0D8BD1DAC39F93B27D4458

# canal admin config
canal.admin.manager = 127.0.0.1:8089
canal.admin.port = 11110
canal.admin.user = admin
canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441
# admin auto register
#canal.admin.register.auto = true
#canal.admin.register.cluster =
#canal.admin.register.name =

canal.serverMode = kafka
canal.mq.flatMessage = true

##################################################
######### 		     Kafka 		     #############
##################################################
kafka.bootstrap.servers = 192.168.1.112:9092
kafka.acks = all
kafka.compression.type = none
kafka.batch.size = 16384
kafka.linger.ms = 1
kafka.max.request.size = 1048576
kafka.buffer.memory = 33554432
kafka.max.in.flight.requests.per.connection = 1
kafka.retries = 0

​ 当确认无误后,进入到deployer下的bin目录,执行命令./startup.sh,通过脚本启动。这个时候deployer已经启动起来了,如果想要停止的话,可执行./stop.sh

​ 配置里面的canal.admin.passwd = 4ACFE3202A5FF5CF467898FC58AAB1D615029441对于不了解的人可能有点懵,其实很简单,就是mysql生成的密码,对应着admin用户的配置。运行select password('admin')得到密码,把前面的*去掉,就是4ACFE3202A5FF5CF467898FC58AAB1D615029441了。

在这里插入图片描述

验证

​ 到了这一步,canal基本上已经没什么问题了,这个时候就需要去验证一下。首先进入logs目录下,查看对应的admin和deployer日志,日志正常表示启动过程无误。这时就可以访问canal的后台了,在浏览器中输入:http://ip:8089/ 访问,默认账号:admin,密码:123456。这默认的账号密码是我们执行canal_manager.sql文件的时候创建的,其中有一段sql语句是这样的。

在这里插入图片描述

​ 如果需要,我们可以自己修改它的SQL脚本,或者在执行后,在数据库里新增或修改canal_user表里的用户数据。通过查看源码可以知道,密码的核心加密方式是SHA-1,进行加密的源码如下:

	public static final String scrambleGenPass(byte[] pass) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] pass1 = md.digest(pass);
        md.reset();
        byte[] pass2 = md.digest(pass1);
        return SecurityUtil.byte2HexStr(pass2);
    }

	/**
     * bytes转换成十六进制字符串
     */
    public static String byte2HexStr(byte[] b) {
        StringBuilder hs = new StringBuilder();
        for (byte value : b) {
            String hex = (Integer.toHexString(value & 0XFF));
            if (hex.length() == 1) {
                hs.append("0" + hex);
            } else {
                hs.append(hex);
            }
        }
        return hs.toString();
    }

​ 在知道了它的加密方式的情况下,我们可以自己调整用户信息。有需要的话,可以自己下载源码调整加密方式后打包重新部署。

注意:若无法访问,可尝试关闭防火墙后再试:systemctl stop firewalld。另,启动防火墙:systemctl start firewalld,查看防火墙状态:systemctl status firewalld。

核心概念

打开页面可以看到,canal-admin提供了集群、server和instance管理。

canal-admin的核心模型主要有:

  1. instance,对应canal-server里的instance,一个最小的订阅mysql的队列
  2. server,对应canal-server,一个server里可以包含多个instance
  3. 集群,对应一组canal-server,组合在一起面向高可用HA的运维

简单解释:

  1. instance因为是最原始的业务订阅诉求,它会和 server/集群 这两个面向资源服务属性的进行关联,比如instance A绑定到server A上或者集群 A上,
  2. 有了任务和资源的绑定关系后,对应的资源服务就会接收到这个任务配置,在对应的资源上动态加载instance,并提供服务
    • 动态加载的过程,有点类似于之前的autoScan机制,只不过基于canal-admin之后可就以变为远程的web操作,而不需要在机器上运维配置文件
  3. 将server抽象成资源之后,原本canal-server运行所需要的canal.properties/instance.properties配置文件就需要在web ui上进行统一运维,每个server只需要以最基本的启动配置 (比如知道一下canal-admin的manager地址,以及访问配置的账号、密码即可)
集群管理

​ 在集群管理下新建一个集群,ZK地址即为zookeeper的地址。
在这里插入图片描述

配置项:

  • 修改集群/删除集群,属于基本的集群信息维护和删除
  • 主配置,主要是指集群对应的canal.properties配置,设计上一个集群的所有server会共享一份全局canal.properties配置 (如果有个性化的配置需求,可以创建多个集群)
  • 查看server,主要是指查看挂载在这个集群下的所有server列表
    在这里插入图片描述

​ 如果要自己修改主配置里的canal.properties,可点击载入模板按钮,之后会自动生成默认的一套模板,这套默认模板其实就是admin下conf目录中的canal-template.properties。在这里修改完成后,点击保存按钮即可。canal.properties的配置即可应用到当前集群上了。
在这里插入图片描述

Server管理

​ 在server管理页面中,点击新建Server按钮,创建一个或多个server。

配置项:

  • 所属集群,可以选择为单机 或者 集群。一般单机Server的模式主要用于一次性的任务或者测试任务
  • Server名称,唯一即可,方便自己记忆
  • Server Ip,机器ip
  • admin端口,canal 1.1.4版本新增的能力,会在canal-server上提供远程管理操作,默认值11110
  • tcp端口,canal提供netty数据订阅服务的端口
  • metric端口, promethues的exporter监控数据端口 (未来会对接监控)

在这里插入图片描述

​ 在完成server配置后,我们可以点击操作,对server进行变更。

在这里插入图片描述

注意:1.在配置了集群的情况下,不允许单独修改server。2.状态为断开时,表示无法连接服务,需检查服务是否正常。并且这时是无法进行启动或停止的操作。

在这里插入图片描述

在这里插入图片描述

正常情况下,状态栏应该是启动。如果状态为停止,可在操作下点击启动尝试启动,如果状态为断开,请查看logs下的日志信息排查问题。
在这里插入图片描述

Instance管理

​ 在Instance管理的管理页面中点击新建Instance按钮,创建一个Instance。
在这里插入图片描述

配置项:

  • 修改,主要就是维护instance.properties配置,做了修改之后会触发对应单机或集群server上的instance做动态reload
  • 删除,相当于直接执行instance stop,并执行配置删除
  • 启动/停止,对instance进行状态变更,做了修改会触发对应单机或集群server上的instance做启动/停止操作
  • 日志,主要针对instance运行状态时,获取对应instance的最后100行日志,比如example/example.log
    在这里插入图片描述

正常情况下,状态栏应该是启动。如果未启动,可在操作下点击启动尝试启动。

在这里插入图片描述

​ 点击会跳转到这个页面,点击载入模板按钮会加载一套默认的instance.properties配置模板,这套默认模板其实就是admin下conf目录中的instance-template.properties。在导入的模板中修改成我们需要的配置。然后选择我们的所属集群,填写Instance名称,点击保存即可。

在这里插入图片描述

​ 这一步最主要的就是关联我们的集群/server(单机)以及维护instance.properties。我自己的配置如下,因为是写的一个例子,所以配置比较简单,也不规范,后期可以根据自己的情况调整。
在这里插入图片描述

​ 其中,canal.instance.filter.regex的配置是mysql 数据解析关注的表,使用Perl正则表达式。多个正则之间以逗号(,)分隔,转义符需要双斜杠(\) 。

常见例子:

  1. 所有表:.* or .\…

  2. canal schema下所有表: canal\…*

  3. canal下的以canal打头的表:canal\.canal.*

  4. canal schema下的一张表:canal.test1

  5. 多个规则组合使用:canal\…*,mysql.test1,mysql.test2 (逗号分隔)

注意:此过滤条件只针对row模式的数据有效(ps. mixed/statement因为不解析sql,所以无法准确提取tableName进行过滤)

​ 另外,canal.mq.topic配置中可以写之前不存在的topic,这样它就会帮我们创建一个新的topic。我们可以结合自己的业务需求,设置匹配规则,建议MQ开启自动。如果像我例子中那样,有可能有时候不够用,多topic的话可以用canal.mq.dynamicTopic,来看看官方的解释。

canal.mq.dynamicTopic 表达式说明

canal 1.1.3版本之后, 支持配置格式:schema 或 schema.table,多个配置之间使用逗号或分号分隔

  • 例子1:test\.test 指定匹配的单表,发送到以test_test为名字的topic上
  • 例子2:.\… 匹配所有表,则每个表都会发送到各自表名的topic上
  • 例子3:test 指定匹配对应的库,一个库的所有表都会发送到库名的topic上
  • 例子4:test\…* 指定匹配的表达式,针对匹配的表会发送到各自表名的topic上
  • 例子5:test,test1\.test1,指定多个表达式,会将test库的表都发送到test的topic上,test1\.test1的表发送到对应的test1_test1 topic上,其余的表发送到默认的canal.mq.topic值

为满足更大的灵活性,允许对匹配条件的规则指定发送的topic名字,配置格式:topicName:schema 或 topicName:schema.table

  • 例子1: test:test\.test 指定匹配的单表,发送到以test为名字的topic上
  • 例子2: test:.\… 匹配所有表,因为有指定topic,则每个表都会发送到test的topic下
  • 例子3: test:test 指定匹配对应的库,一个库的所有表都会发送到test的topic下
  • 例子4:testA:test\…* 指定匹配的表达式,针对匹配的表会发送到testA的topic下
  • 例子5:test0:test,test1:test1\.test1,指定多个表达式,会将test库的表都发送到test0的topic下,test1\.test1的表发送到对应的test1的topic下,其余的表发送到默认的canal.mq.topic值

​ 另外,多分区,可以使用canal.mq.partitionsNum、canal.mq.partitionHash,它们主要控制是否多分区以及分区的partition的路由计算,针对命中条件的可以做到按表级做分区、pk级做分区等,canal.mq.partitionsNum是用来设置散列模式的分区数,而canal.mq.partitionHash和canal.mq.dynamicTopic类似,来看看官方的解释。

canal.mq.partitionHash 表达式说明

canal 1.1.3版本之后, 支持配置格式:schema.table:pk1^pk2,多个配置之间使用逗号分隔

  • 例子1:test\.test:pk1^pk2 指定匹配的单表,对应的hash字段为pk1 + pk2
  • 例子2:.\…:id 正则匹配,指定所有正则匹配的表对应的hash字段为id
  • 例子3:.\…: p k pk pk 正则匹配,指定所有正则匹配的表对应的hash字段为表主键(自动查找)
  • 例子4: 匹配规则啥都不写,则默认发到0这个partition上
  • 例子5:.\… ,不指定pk信息的正则匹配,将所有正则匹配的表,对应的hash字段为表名
    • 按表hash: 一张表的所有数据可以发到同一个分区,不同表之间会做散列 (会有热点表分区过大问题)
  • 例子6: test\.test:id,.\…* , 针对test的表按照id散列,其余的表按照table散列

注意:大家可以结合自己的业务需求,设置匹配规则,多条匹配规则之间是按照顺序进行匹配(命中一条规则就返回)

​ 更多详细信息可查看官网对支持的MQ的解释:https://github.com/alibaba/canal/wiki/Canal-Kafka-RocketMQ-QuickStart

​ 最后如何验证我们的instance配置是否生效,可以在我们的deployer下的conf目录下,看到一个与我们创建的instance同名的文件夹,我们刚刚创建的instance名称为example-canal,这个文件夹在最开始的时候肯定没有的,而是在我们创建完这个instance后生成的,这时就表明我们的instance创建成功了。

在这里插入图片描述

创建测试表

​ 为了测试,我就在canal_manger库下创建了一张测试用的表。这张表就是刚刚在instance.properties中库表表达式里指向的表,SQL脚本如下,当然这只是测试,做法并不规范。

CREATE TABLE `canal_test` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `context` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '内容',
  `insert_time` datetime DEFAULT NULL COMMENT '插入时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='canal测试表';

​ 在创建了表之后,我们可以通过新增一条数据去测试我们刚刚的部署和配置是否成功。

INSERT INTO `canal_manager`.`canal_test`(`id`, `context`, `insert_time`) VALUES (8, '测试', '2021-10-09 15:04:41');
完成验证

​ 最后一步就是查看kafka的数据,看看mysql中添加的数据是否真的会传到kafka中。查看kafka数据的方式有很多,我这里通过一个可视化工具kafka tool进行查看,安装也很简单,选择一个本地安装目录,然后下一步下一步就完事了。这里附上官网下载地址:https://www.kafkatool.com/download.html

​ 通过kafka tool工具可以看到,里面有一个canal-kafka-test的topic,这个topic是我之前没有的,也就是说instance.properties配置已经生效了,它已经帮我创建好了。另外可以看到canal-kafka-test的下面有我们之前在mysql数据库中添加的数据,当然我之前测试时就已经反复添加和删除过多条数据了,所以截图里可以看到其实是有8条数据的。
在这里插入图片描述

​ 如果在使用kafka tool工具的时候发现有这种情况,message中的数据不像是我们原本的数据,那可以修改一下这里的配置,将点击canal-kafka-test,把key和message对应的content types都从Byte Array改为String就可以了。

在这里插入图片描述

在这里插入图片描述

到这里,基本上已经没有什么问题了,验证成功。

canal客户端

​ canal提供了canal客户端API,可以帮助我们连接canal服务,消费数据。由于我的例子里没有要用到客户端的地方,并且官方提供了完整的API和样例代码。我直接上链接:https://github.com/alibaba/canal/wiki/ClientExample

全量同步

​ 在canal做增量同步之前,我们一般需要做一次全量同步,不然以前的数据就没有同步过来。canal也提供了全量同步的方法,目前我找到的有两种:1.在instance.properties中是可以进行配置的,2.通过ClientAdapter进行全量同步。

ClientAdapter

​ ClientAdapter顾名思义,就是canal提供的适配器,相当于客户端,会从canal-server中获取数据,然后对数据进行同步,增量同步全量同步都可以用它。具体什么意思呢,就是说我们可以偷个懒,不用通过ClientAPI去编写我们的客户端了,直接拿着ClientAdapter改一改里面的配置就能用,当然,个性化需求得需要我们自己编写客户端去实现

​ 在使用前,先从官网中下载下来。如图所示,下载canal.adapter-1.1.5.tar.gz,安装包官网下载地址:https://github.com/alibaba/canal/releases

在这里插入图片描述

​ 下载后我们可以解压出来看看,找到adapter下的conf目录,可以看到1.1.5版本是支持的哪几种,有es、hbase、kudu、rdb(关系型数据库)。

在这里插入图片描述

​ 然后我们可以看看application.yml里面是怎么样的。

server:
  port: 8081
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    default-property-inclusion: non_null

canal.conf:
  #客户端消费模式,对应下面的consumerProperties
  mode: tcp #tcp kafka rocketMQ rabbitMQ
  #是否以json字符串传递数据,仅对mq生效
  flatMessage: true
  #集群配置
  zookeeperHosts:
  #每次同步的批数量
  syncBatchSize: 1000
  #重试次数,-1为无限次
  retries: 0
  #配置超时
  timeout:
  #下面是安全密钥配置
  accessKey:
  secretKey:
  consumerProperties:
    # canal tcp consumer  连接canal server的配置
    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 consumer  连接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 consumer  连接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 consumer  连接rabbitMQ的配置
    rabbitmq.host:
    rabbitmq.virtual.host:
    rabbitmq.username:
    rabbitmq.password:
    rabbitmq.resource.ownerId:

#数据源
#  srcDataSources:  
#    defaultDS:
#      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true
#      username: root
#      password: 121212
#下面开始canal适配器的配置
  canalAdapters:
  - instance: example # canal instance Name or mq topic name
    groups:
    - groupId: g1   #一份数据可被多个groupId消费,同groupId并发执行,同一groupId内的adapters顺序执行
      outerAdapters:  #输出配置
      - name: logger  #日志
      #输出到关系型数据库,也就是rdb
#      - name: rdb
#        key: mysql1    #这个是输出到mysql
#        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   #这个是输出到oracle
#        properties:
#          jdbc.driverClassName: oracle.jdbc.OracleDriver
#          jdbc.url: jdbc:oracle:thin:@localhost:49161:XE
#          jdbc.username: mytest
#          jdbc.password: m121212
#      - name: rdb
#        key: postgres1  #这个是输出到postgres
#        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  #这个是输出到hbase
#        properties:
#          hbase.zookeeper.quorum: 127.0.0.1
#          hbase.zookeeper.property.clientPort: 2181
#          zookeeper.znode.parent: /hbase
#      - name: es   #这个是输出到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  #这个是输出到kudu
#          key: kudu
#          properties:
#            kudu.master.address: 127.0.0.1 # ',' split multi address

​ 可以看到,上游支持的消息来源有canal server、kafka、rocketMQ、rabbitMQ,下游支持接收的有mysql、oracle、postgres、hbase、es、kudu。那大概怎么配置其实也可以猜到了,就是先将总配置文件application.yml配置好,然后进入到具体的文件夹中去配置适配器表映射文件。比如:现在我想要输出到hbase,那么我先把application.yml配置好,然后进入到hbase目录下继续hbase的相关配置。然后有需要的话,再调整一下其他配置,最后直接启动canal adapter。

​ 那么具体怎么配置,怎么使用的,那当然是看官网了,官网地址:https://github.com/alibaba/canal/wiki/ClientAdapter。如果还是不清楚的,借用一下这位大神的文章,讲的很清楚:https://blog.csdn.net/Day_Day_No_Bug/article/details/116748553

instance.properties

​ 因为本次例子是实现mysql->kafka场景,所以用ClientAdapter不太现实,那就还有另一种方式。在instance.properties中,其实就已经提供了一种全量同步的方式,那就是通过下面三项配置,去指定读取binlog日志中的数据。在我们新增instance的时候,可以在instance.properties里配置一下,下面是我的例子。
在这里插入图片描述

# mysql日志文件,起始的binlog文件
canal.instance.master.journal.name=mysql-bin.000080
# 获取日志的起始binlog位点,一般写个0就行,因为全量同步基本上都是全部数据都要
canal.instance.master.position=0
# 获取日志的起始时间戳
canal.instance.master.timestamp=1634110736

​​ binglog文件名,可以通过show master logs获取mysql binlog日志列表。canal.instance.master.journal.name指向的哪个binlog,就从哪个日志文件开始读取。
在这里插入图片描述​ 通过show binlog events in 'mysql-bin.000082'命令可以查看日志,里面包含了位点信息。
在这里插入图片描述

​​ 其实这3个属性设置,主要就是用来定位具体binlog位点,好让canal知道从哪个binlog文件,binlog文件的哪个位置开始进行同步(注意:这只是我们进行全量同步的配置,如果不指定任何信息,默认从当前数据库的位点,进行启动。在mysql执行这个命令:show master status,可查看位点状态),方式有两个:

  1. 通过canal.instance.master.journal.name+canal.instance.master.position的方式定位,精确指定一个binlog位点,进行启动。

    # binlog日志文件名
    canal.instance.master.journal.name='mysql-bin.000082'
    # binlog具体位点
    canal.instance.master.position=3329
    
  2. 通过canal.instance.master.timestamp时间戳定位,指定一个时间戳,canal会自动遍历mysql binlog,找到对应时间戳的binlog位点后,进行启动。

    # 时间戳
    canal.instance.master.timestamp=1634110736
    

canal.instance.master.timestamp是需要填写时间戳的,如果对时间戳没什么概念,那么可以网上搜索时间戳转换器,它可以帮我们转换时间戳。

在这里插入图片描述

在这里插入图片描述​ 新增完成后,需要在instance管理启动我们的instance,启动之后等一段时间,就可以去查看一下我们的MQ中是否已经有之前的历史数据了。如果有,就表示全量同步完成。
在这里插入图片描述

​ 如果是之前就已经新增了instance,可以找到对应的instance直接点击修改,进入页面调整instance.properties。
在这里插入图片描述

​ 修改了instance.properties文件后,找到当初生成的instance目录,将里面的meta.dat删除,因为这个文件记录了当前instance的状态信息。如果还把它留着的话,那么有可能不会生效。可以看看里面的内容,里面包含了消费的位置、时间戳、日志文件、数据库ip端口,客户端等等一系列的信息。

在这里插入图片描述
​ 在instance管理中将刚刚修改的instance先停止,然后再启动一下就行了,这个时候刚刚增加的全量同步配置就会生效。如果最后不行,可以手动重启一下canal试试。
在这里插入图片描述

​ 如果以上方式不行,那就来个粗暴点的方式,找到刚刚的meta.dat文件,直接修改里面的内容,将 "position"的值改成4, 将"journalName"改成起始binlog文件名,timestamp时间戳要改到你想读取数据的位置,保存后重启canal。但是这种方式我不知道能不能行,网上找到的,感觉上能成。

拓展

​ 因为自身的一些业务需求,有时候我们可能想要一些canal本身没有提供的功能。比如,对于canal用户的密码,不想使用SHA-1,想用MD5或者自己的一套加密算法,又或者对于放入MQ的message我想使用自己定义的一套json格式的数据,不想使用官方原本定义的json格式。这些都是可以实现的,因为官方是开源的,很多东西都可以自己操作,这就是开源的好处之一。

​ 就拿刚刚举的两个例子,其实官方并没有提供能够操作的接口,但是canal是开源的呀,所以可以自己改代码。源码就是官网上的最后两个,根据实际情况随便下载其中一个即可,我是下载的zip。
在这里插入图片描述

  1. 修改加密方式:我们可以通过找到修改密码的地方去寻找加密方式,其实修改用户密码是通过调用修改用户信息接口,直接找到加密工具类进行加密,就是下面截图里的这样。都已经找到加密的方式了,那么接下来修改也就很简单了。

在这里插入图片描述

在这里插入图片描述

  1. 自定义json:其实最主要的就是找到FlatMessage这个类,可以看到FlatMessage类的属性和我们message中的数据格式是一样的。如果需要自定义json,那么只需要把FlatMessage类按照自己的需求修改了,然后将其他有用到FlatMessage类的地方也一同修改了就完成了。

在这里插入图片描述

在这里插入图片描述

​ 以上两个例子只是很简单的调整,但是如果有复杂的调整也是一样的操作。当按照自己的需求调整完成后,打包源代码,重新部署一下就好了。

;