1、Canal背景
早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求。不过早期的数据库同步业务,主要是基于trigger的方式获取增量变更,不过从2010年开始,阿里系公司开始逐步的尝试基于数据库的日志解析,获取增量变更进行同步,由此衍生出了增量订阅&消费的业务,从此开启了一段新纪元。
2、Canal原理
2.1mysql主备复制实现
从上层来看,复制分成三步:
master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);
slave将master的binary log events拷贝到它的中继日志(relay log);
slave重做中继日志中的事件,将改变反映它自己的数据。
2.2canal的工作原理:
canal模拟mysql slave的交互协议,伪装自己为mysql slave,向mysql master发送dump协议
mysql master收到dump请求,开始推送binary log给slave(也就是canal)
canal解析binary log对象(原始为byte流)
3、Canal的配置文件
canal配置方式有两种:
- ManagerCanalInstanceGenerator: 基于manager管理的配置方式,目前alibaba内部配置使用这种方式
- SpringCanalInstanceGenerator:基于本地spring xml的配置方式,目前开源版本已经自带该功能所有代码,大部采用此种方式
3.1Spring配置
spring配置的原理是将整个配置抽象为两部分:
- xxxx-instance.xml:
conf/spring目录下的配置文件,如(memory/file/default/group)-instance.xml,canal组件的配置定义。
- xxxx.properties:
包含系统根配置文件canal.properties和instance.properties(定义不同的数据库实例)每个instance通道都有各自一份定义,因为每个mysql的ip,帐号,密码等信息不会相同
3.1.1xxxx-instance.xml
在介绍instance配置之前,先了解一下canal如何维护一份增量订阅&消费的关系信息:
- 解析位点 (parse模块会记录,上一次解析binlog到了什么位置,对应组件为:CanalLogPositionManager)
- 消费位点 (canal server在接收了客户端的ack后,就会记录客户端提交的最后位点,对应的组件为:CanalMetaManager)
那么,在canal中是如何配置实现的呢?通过在canal的根配置文件中(canal.properties),指定当前canal启动时,采用那种方式来定义组件,默认是文件方式:
定义的组件包括:
eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)、eventSink (Parser和Store链接器,进行过滤(表、字段),路由分发,归并,加工的工作)、eventStore (数据存储--记录存储、消费、订阅的位置信息)、metaManager (增量订阅&消费信息管理器)
3.1.1.1memory-instance.xml
所有的组件(parser , sink , store)都选择了内存版模式,记录位点的都选择了memory模式,重启后又会回到初始位点进行解析 。
特点:速度最快,依赖最少(不需要zookeeper)
场景:一般应用在quickstart,或者是出现问题后,进行数据分析的场景,不应该将其应用于生产环境
3.1.1.2default-instance.xml
store选择了内存模式,其余的parser/sink依赖的位点管理选择了持久化模式,目前持久化的方式主要是写入zookeeper,保证数据集群共享.
特点:支持canalServer HA
场景:生产环境,集群化部署----我们采用此方式
3.1.1.3group-instance.xml
主要针对需要进行多库合并时,可以将多个物理instance(数据库实例)合并为一个逻辑instance,提供客户端访问。
场景:分库业务。 比如产品数据拆分了4个库,每个库会有一个instance(canal解压后的conf目录下包含instance.properties的文件夹),如果不用group,业务上要消费数据时,需要启动4个客户端(在客户端指定destination),分别链接4个instance实例。使用group后,可以在canal server上合并为一个逻辑instance,只需要启动1个客户端,链接这个逻辑instance即可
3.1.2xxxx-properties
xxxx-properties配置分为两部分:
canal.properties---- 系统根配置文件-canalServer的启动配置
instance.properties----instance级别的配置文件,每个instance(数据库)一份
注意:instance.properties配置定义优先级高于canal.properties
3.1.2.1canal.properties
参数名字 | 参数说明 | 默认值 |
canal.destinations | 当前server上部署的instance列表 | 无 |
canal.conf.dir | conf/目录所在的路径 | ../conf |
canal.auto.scan | 开启instance自动扫描 | true |
canal.auto.scan.interval | instance自动扫描的间隔时间,单位秒 | 5 |
canal.instance.global.mode | 全局配置加载方式 | spring |
canal.instance.global.lazy | 全局lazy模式 | false |
canal.instance.global.manager.address | 全局的manager配置方式的链接信息 | 无 |
canal.instance.global.spring.xml | 全局的spring配置方式的组件文件 | classpath:spring/memory-instance.xml |
canal.instance.example.mode | instance级别的配置定义,如有配置,会自动覆盖全局配置定义模式 | 无 |
canal.instance.tsdb.spring.xml | v1.0.25版本新增,全局的tsdb配置方式的组件文件 | classpath:spring/tsdb/h2-tsdb.xml (spring目录相对于canal.conf.dir) |
通用参数定义 | ||
参数名字 | 参数说明 | 默认值 |
canal.id | 每个canal server实例的唯一标识,暂无实际意义 | 1 |
canal.ip | canal server绑定的本地IP信息,如果不配置,默认选择一个本机IP进行启动服务 | 无 |
canal.port | canal server提供socket服务的端口 | 11111 |
canal.zkServers | canal server链接zookeeper集群的链接信息 | 无 |
canal.zookeeper.flush.period | canal持久化数据到zookeeper上的更新频率,单位毫秒 | 1000 |
canal.instance.memory.batch.mode | canal内存store中数据缓存模式 | MEMSIZE |
canal.instance.memory.buffer.size | canal内存store中可缓存buffer记录数,需要为2的指数 | 16384 |
canal.instance.memory.buffer.memunit | 内存记录的单位大小,默认1KB,和buffer.size组合决定最终的内存使用大小 | 1024 |
canal.instance.transactionn.size | 最大事务完整解析的长度支持 | 1024 |
canal.instance.fallbackIntervalInSeconds | canal发生mysql切换时,在新的mysql库上查找binlog时需要往前查找的时间,单位秒 | 60 |
canal.instance.detecting.enable | 是否开启心跳检查 | false |
canal.instance.detecting.sql | 心跳检查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 | 心跳检查失败后,是否开启自动mysql自动切换 | false |
canal.instance.network.receiveBufferSize | 网络链接参数,SocketOptions.SO_RCVBUF | 16384 |
canal.instance.network.sendBufferSize | 网络链接参数,SocketOptions.SO_SNDBUF | 16384 |
canal.instance.network.soTimeout | 网络链接参数,SocketOptions.SO_TIMEOUT | 30 |
canal.instance.filter.druid.ddl | 是否使用druid处理所有的ddl解析来获取库和表名 | true |
canal.instance.filter.query.dcl | 是否忽略dcl语句 | false |
canal.instance.filter.query.dml | 是否忽略dml语句 | false |
canal.instance.filter.query.ddl | 是否忽略ddl语句 | false |
canal.instance.filter.table.error | 是否忽略binlog表结构获取失败的异常 (主要解决回溯binlog时,对应表已被删除或者表结构和binlog不一致的情况) | false |
canal.instance.filter.rows | 是否dml的数据变更事件 (主要针对用户只订阅ddl/dcl的操作) | false |
canal.instance.filter.transaction.entry | 是否忽略事务头和尾,比如针对写入kakfa的消息时,不需要写入TransactionBegin/Transactionend事件 | false |
canal.instance.binlog.format | 支持的binlog format格式列表 | ROW,STATEMENT,MIXED |
canal.instance.binlog.image | 支持的binlog image格式列表 | FULL,MINIMAL,NOBLOB |
canal.instance.get.ddl.isolation | ddl语句是否单独一个batch返回 (比如下游dml/ddl如果做batch内无序并发处理,会导致结构不一致) | false |
canal.instance.parser.parallel | 是否开启binlog并行解析模式 (串行解析资源占用少,但性能有瓶颈, 并行解析可以提升近2.5倍+) | true |
canal.instance.parser.parallelBufferSize | binlog并行解析的异步ringbuffer队列 | 256 |
canal.instance.tsdb.enable | 是否开启tablemeta的tsdb能力 | true |
canal.instance.tsdb.dir | 主要针对h2-tsdb.xml时对应h2文件的存放目录,默认为conf/xx/h2.mv.db | ${canal.file.data.dir:../conf}/${canal.instance.destination:} |
canal.instance.tsdb.url | jdbc url的配置 (h2的地址为默认值,如果是mysql需要自行定义) | jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_S IZE=1000;MODE=MYSQL; |
canal.instance.tsdb.dbUsername | jdbc url的配置 (h2的地址为默认值,如果是mysql需要自行定义) | canal |
canal.instance.tsdb.dbPassword | jdbc url的配置 (h2的地址为默认值,如果是mysql需要自行定义) | canal |
canal.instance.rds.accesskey | aliyun账号的ak信息 (如果不需要在本地binlog超过18小时被清理后自动下载oss上的binlog,可以忽略该值) | 无 |
canal.instance.rds.secretkey | aliyun账号的sk信息 (如果不需要在本地binlog超过18小时被清理后自动下载oss上的binlog,可以忽略该值) | 无 |
3.1.2.2instance.properties
在canal.properties定义了canal.destinations后,需要在canal.conf.dir对应的目录下建立同名的文件,比如:canal.destinations = example1,example2,这时需要创建example1和example2两个目录,每个目录里各自有一份instance.properties。canal自带了一份instance.properties,可直接复制conf/example目录进行配置修改
cp -R example example1/
cp -R example example2/
如果canal.properties未定义instance列表,但开启了canal.auto.scan时,server第一次启动时,会自动扫描conf目录下,将文件名做为instance name,启动对应的instance,canalServer运行过程中,会根据canal.auto.scan.interval定义的频率,进行扫描
1. 发现目录有新增,启动新的instance
2. 发现目录有删除,关闭老的instance
3. 发现对应目录的instance.properties有变化,重启instance
instance.properties参数列表 | ||
参数名字 | 参数说明 | 默认值 |
canal.instance.mysql.slaveId | mysql集群配置中的serverId概念,需要保证和当前mysql集群中id唯一 | 无 |
canal.instance.master.address | mysql主库链接地址 | 127.0.0.1:3306 |
canal.instance.master.journal.name | mysql主库链接时起始的binlog文件 | 无 |
canal.instance.master.position | mysql主库链接时起始的binlog偏移量 | 无 |
canal.instance.master.timestamp | mysql主库链接时起始的binlog的时间戳 | 无 |
canal.instance.gtidon | 是否启用mysql gtid的订阅模式 | false |
canal.instance.master.gtid | mysql主库链接时对应的gtid位点 | 无 |
canal.instance.dbUsername | mysql数据库帐号 | canal |
canal.instance.dbPassword | mysql数据库密码 | canal |
canal.instance.defaultDatabaseName | mysql链接时默认schema | |
canal.instance.connectionCharset | mysql 数据解析编码 | UTF-8 |
canal.instance.filter.regex | mysql 数据解析关注的表,Perl正则表达式. 多个正则之间以逗号(,)分隔,转义符需要双斜杠(\\)
1. 所有表:.* or .*\\..* 5. 多个规则组合使用:canal\\..*,mysql.test1,mysql.test2 (逗号分隔) | .*\\..* |
canal.instance.filter.black.regex | mysql 数据解析表的黑名单,表达式规则见白名单的规则 | 无 |
canal.instance.rds.instanceId | aliyun rds对应的实例id信息 (如果不需要在本地binlog超过18小时被清理后自动下载oss上的binlog,可以忽略该值) |
4、HA模式配置
4.1HA原理
在Canal的设计中,基于对容灾的考虑,往往会配置两个或更多个CanalServer来负责一个MySQL数据库实例的数据增量复制。canal的ha分为两部分,canal server和canal client分别有对应的ha实现,整个HA机制的控制主要是依赖了zookeeper的几个特性,watcher和EPHEMERAL节点(和session生命周期绑定)
1、canal server: 为了减少对mysql dump的请求,不同server上的instance要求同一时间只能有一个处于running,其他的处于standby状态.
2、canal client: 为了保证有序性,一份instance同一时间只能由一个canal client进行get/ack/rollback操作,否则客户端接收无法保证有序。
大致步骤:
1、canal server要启动某个canal instance时都先向zookeeper进行一次尝试启动判断 (实现:创建EPHEMERAL节点,谁创建成功就允许谁启动)
2、创建zookeeper节点成功后,对应的canal server就启动对应的canal instance,没有创建成功的canal instance就会处于standby状态
3、一旦zookeeper发现canal server A创建的节点消失后,立即通知其他的canal server再次进行步骤1的操作,重新选出一个canal server启动instance.
4、canal client每次进行connect时,会首先向zookeeper询问当前是谁启动了canal instance,然后和其建立链接,一旦链接不可用,会重新尝试connect.
Canal Client的HA方式和canal server方式类似,也是利用zookeeper的抢占EPHEMERAL节点的方式进行控制.
4.2实施配置
参考https://blog.csdn.net/feiying0canglang/article/details/105612204
4.2.1下载canal
4.2.2上传到服务器
1、解压配置canal.properties |
|
创建mvsbase文件夹 |
修改instance.properties
|
修改下图配置,否则当表结构发生变化时,由于binlog数据包含以前表结构的数据,此时cannal解析时就会 parse row data fail
|
启动canal: sh startup.sh
|
4.2.3canalServer高可用
拷贝4.2.2的canal在另一台机器上部署canalserver,配置一模一样。
启动后查看zookeeper:
ls /otter/canal/cluster: |
停掉46再次查看ls /otter/canal/cluster: |
启动46查看ls /otter/canal/destinations/mvsbase/cluster |
查看mvsbase(代表监控的mysql)
|
停止56查看ls /otter/canal/destinations/mvsbase/cluster |
查看get /otter/canal/destinations/mvsbase/running |