canal工作原理及简单案例演示

如果有一个这样的需求,数据修改后,需要及时将mysql中修改的记录同步到elasticsearch中,我们怎么来实现呢?
思考30s…,带着这个疑问我们来看一下canal如何为我们解决的

1.CANAL是什么

canal是阿里巴巴旗下的一款开源项目,纯Java开发。
https://github.com/alibaba/canal

1.1. CANAL的历史

  • canal [kə’næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费
  • 早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

1.2. CANAL的功能

在这里插入图片描述

  • 基于日志增量订阅和消费的业务包括
  1. 数据库镜像
  2. 数据库实时备份
  3. 索引构建和实时维护(拆分异构索引、倒排索引等
  4. 业务 cache 刷新
  5. 带业务逻辑的增量数据处理
  6. 当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.x , 5.7.x , 8.0.x
  7. canal 作为 MySQL binlog 增量获取和解析工具,可将变更记录投递到 MQ 系统中,比如 Kafka/RocketMQ,可以借助于 MQ 的多语言能力
  • canal 特别设计了 client-server 模式,交互协议使用 protobuf 3.0 , client 端可采用不同语言实现不同的消费逻辑
  1. canal java 客户端: https://github.com/alibaba/canal/wiki/ClientExample
  2. canal c# 客户端:
    https://github.com/dotnetcore/CanalSharp
  3. canal go客户端:
    https://github.com/CanalClient/canal-go
  4. canal php客户端:
    https://github.com/xingwenge/canal-php
  5. canal Python客户端:
    https://github.com/haozi3156666/canal-python
  6. canal Rust客户端:
    https://github.com/laohanlinux/canal-rs

2.CANAL的工作原理

2.1. mysql主备工作原理

在这里插入图片描述
从上层来看,复制分成三步:

  1. MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
 show binlog events

在这里插入图片描述

  1. MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
  2. MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据

2.2 canal 工作原理

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

2.3. 基础架构

在这里插入图片描述
说明:

  • server代表一个canal运行实例,对应于一个jvm
  • instance对应于一个数据队列 (1个server对应1…n个instance)

instance模块:

  • eventParser (数据源接入,模拟slave协议和master进行交互,协议解析)
  • eventSink (Parser和Store链接器,进行数据过滤,加工,分发的工作)
  • eventStore (数据存储)
    metaManager (增量订阅&消费信息管理器)
    在这里插入图片描述
    在这里插入图片描述

2.3.1 科普一下:mysql的Binlay Log介绍

简单点说:

  • mysql的binlog是多文件存储,定位一个LogEvent需要通过binlog filename + binlog position,进行定位
  • mysql的binlog数据格式,按照生成的方式,主要分为:statement-based、row-based、mixed。
    在这里插入图片描述
    目前canal支持所有模式的增量订阅(但配合同步时,因为statement只有sql,没有数据,无法获取原始的变更日志,所以一般建议为ROW模式)

2.3.2 EventParser的设计与实现奥妙

首先我们先从官方文档来看 EventParser 的整体设计,其架构设计图如下所示:
在这里插入图片描述
上述图罗列出了 EventParser 的整体工作流程图,其关键步骤如下:

  1. 从 Log Position 管理器中获取上一次解析的日志位点。
  2. 向 Mysql Master 节点发送 BINLOG_DUMP 请求。
  3. Mysql Master 节点从 Slave 端传入的日志位点开始向从节点推送 binlog 日志。
  4. Slave 接收 binlog 日志,调用 BinlogParser 解析 binlog日志。
  5. 将解析后的结构化数据传入到 EventSink 组件。
  6. 定时记录解析 binlog 的日志,以便重启后继续进行增量订阅。
  7. 上图中还罗列一个HA 特性,即需要同步的 Master 如果宕机,可以从它的其他从节点继续同步 binlog 日志,避免单点故障。

2.3.3 EventSink的设计与实现奥妙

在这里插入图片描述
说明:

  1. 数据过滤:支持通配符的过滤模式,表名,字段内容等

  2. 数据路由/分发:解决1:n (1个parser对应多个store的模式)

  3. 数据归并:解决n:1 (多个parser对应1个store)

  4. 数据加工:在进入store之前进行额外的处理,比如join

2.3.3.1 数据1:n业务
  • 为了合理的利用数据库资源, 一般常见的业务都是按照schema进行隔离,然后在mysql上层或者dao这一层面上,进行一个数据源路由,屏蔽数据库物理位置对开发的影响,阿里系主要是通过cobar/tddl来解决数据源路由问题。

  • 所以,一般一个数据库实例上,会部署多个schema,每个schema会有由1个或者多个业务方关注

2.3.3.2 数据n:1业务
  • 同样,当一个业务的数据规模达到一定的量级后,必然会涉及到水平拆分和垂直拆分的问题,针对这些拆分的数据需要处理时,就需要链接多个store进行处理,消费的位点就会变成多份,而且数据消费的进度无法得到尽可能有序的保证。

  • 所以,在一定业务场景下,需要将拆分后的增量数据进行归并处理,比如按照时间戳/全局id进行排序归并.

2.3.4 EventStore的设计与实现奥妙

  1. 目前仅实现了Memory内存模式,后续计划增加本地file存储,mixed混合模式
  2. 借鉴了Disruptor的RingBuffer的实现思路
    在这里插入图片描述
    定义了3个cursor:
    Put : Sink模块进行数据存储的最后一次写入位置
    Get : 数据订阅获取的最后一次提取位置
    Ack : 数据消费成功的最后一次消费位置

借鉴Disruptor的RingBuffer的实现,将RingBuffer拉直来看:
在这里插入图片描述
实现说明:
Put/Get/Ack cursor用于递增,采用long型存储
buffer的get操作,通过取余或者与操作。(与操作: cusor & (size - 1) , size需要为2的指数,效率比较高)

2.3.5 Instance设计

在这里插入图片描述

  • instance代表了一个实际运行的数据队列,包括了EventPaser,EventSink,EventStore等组件。

抽象了CanalInstanceGenerator,主要是考虑配置的管理方式:

  • manager方式: 和你自己的内部web console/manager系统进行对接
  • spring方式:基于spring xml + properties进行定义,构建spring配置.

2.3.6 Server设计

在这里插入图片描述
server代表了一个canal的运行实例,为了方便组件化使用,特意抽象了Embeded(嵌入式) / Netty(网络访问)的两种实现

Embeded : 对latency和可用性都有比较高的要求,自己又能hold住分布式的相关技术(比如failover)
Netty : 基于netty封装了一层网络协议,由canal server保证其可用性,采用的pull模型,当然latency会稍微打点折扣,不过这个也视情况而定。(阿里系的notify和metaq,典型的push/pull模型,目前也逐步的在向pull模型靠拢,push在数据量大的时候会有一些问题)

2.3.7 HA机制设计

canal的ha分为两部分,canal server和canal client分别有对应的ha实现

  • canal server:
    为了减少对mysql dump的请求,不同server上的instance要求同一时间只能有一个处于running,其他的处于standby状态.
  • canal client:
    为了保证有序性,一份instance同一时间只能由一个canal client进行get/ack/rollback操作,否则客户端接收无法保证有序。
    整个HA机制的控制主要是依赖了zookeeper的几个特性,watcher和EPHEMERAL节点(和session生命周期绑定),可以看下我之前zookeeper的相关文章。
    在这里插入图片描述大致步骤:
    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的方式和canal server方式类似,也是利用zookeeper的抢占EPHEMERAL节点的方式进行控制。

到此,canal历史与基础原理介绍完毕,下面看展实战演练,大家加油!


3. CANAL应用-QuickStart

3.1 准备工作:

3.1.1 启动mysql服务

在这里插入图片描述

3.1.2 开启binlog

对于自建 MySQL , 需要先开启 Binlog 写入功能,配置 binlog-format 为 ROW 模式,my.cnf 中配置如下

[mysql@test1 mysql]$ sudo vim /etc/my.cnf
[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复

注意:针对阿里云 RDS for MySQL , 默认打开了 binlog , 并且账号默认具有 binlog dump 权限 , 不需要任何权限或者 binlog 设置,可以直接跳过这一步

[mysql@test1 mysql]$ sudo vim /etc/my.cnf
[mysqld]
log-bin=/usr/local/mysql/mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=7 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复

[mysql@test1 mysql]$ service mysqld restart   #重新启动
Shutting down MySQL....[  OK  ]
Starting MySQL.[  OK  ]

在这里插入图片描述
启动完成后,查看主库状态

mysql> show master status;

在这里插入图片描述
查看binlog_format模式

mysql> show variables like 'binlog_format';

在这里插入图片描述

3.1.3 授权

授权 canal 链接 MySQL 账号具有作为 MySQL slave 的权限, 如果已有账户可直接 grant

[mysql@test1 mysql]$ mysql -uroot -pmysql123  #登录数据库

CREATE USER canal IDENTIFIED BY 'canal';  
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
--GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;
FLUSH PRIVILEGES;

在这里插入图片描述

3.1.4 下载-启动

下载 canal, 访问 release 页面 , 选择需要的包下载, 如以 1.1.4 版本为例
release 页面 :https://github.com/alibaba/canal/releases
在这里插入图片描述

wget https://github.com/alibaba/canal/releases/download/canal-1.1.4/canal.deployer-1.1.4.tar.gz

解压缩

mkdir /opt/canal
tar zxvf canal.deployer-$version.tar.gz  -C /opt/canal

解压目录

解压完成后,进入 /opt/canal 目录,可以看到如下结构
[root@test1 software]# cd ../canal/
[root@test1 canal]# ll
total 4
drwxr-xr-x. 2 root root   76 Aug 12 16:39 bin
drwxr-xr-x. 5 root root  123 Aug 12 16:39 conf
drwxr-xr-x. 2 root root 4096 Aug 12 16:39 lib
drwxrwxrwx. 2 root root    6 Sep  2  2019 logs

修改配置

vim conf/example/instance.properties
## mysql serverId
canal.instance.mysql.slaveId = 1234
#position info,需要改成自己的数据库信息
canal.instance.master.address = 192.168.27:3306 
canal.instance.master.journal.name = 
canal.instance.master.position = 
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 =testdb
canal.instance.connectionCharset = UTF-8
#table regex
canal.instance.filter.regex = .\*\\\\..\*

canal.instance.connectionCharset 代表数据库的编码方式对应到 java 中的编码类型,比如 UTF-8,GBK , ISO-8859-1
如果系统是1个 cpu,需要将 canal.instance.parser.parallel 设置为 false

启动

sh bin/startup.sh

查看 server 日志

vi logs/canal/canal.log</pre>

在这里插入图片描述

查看 instance 的日志

vi logs/example/example.log

在这里插入图片描述

关闭

sh bin/stop.sh

必须安装JDK

which: no java in (/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/mysql/bin)
Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH.

3.2. 案例演示-ClientExample

  1. 使用IDEA创建maven工程canal-client-example

修改pom.xml,添加依赖:

<dependency>
    <groupId>com.alibaba.otter</groupId>
    <artifactId>canal.client</artifactId>
    <version>1.1.0</version>
</dependency>

2.创建SimpleCanalClientExample.java文件
修改链接配置,canal.instance.defaultDatabaseName=testdb 数据库为testdb
在这里插入图片描述
在这里插入图片描述
确保配置一致

3.启动canal-client-example项目后,在testdb.tb_customer插入两条数据
在这里插入图片描述

INSERT INTO `tb_customer` VALUES ('3', '张三', '23');
INSERT INTO `tb_customer` VALUES ('4', '李四', '24');

启动工程
在这里插入图片描述
查看console控制台日志输出
在这里插入图片描述


4.canal-admin介绍与搭建

canal-admin设计上是为canal提供整体配置管理、节点运维等面向运维的功能,提供相对友好的WebUI操作界面,方便更多用户快速和安全的操作

canal-admin的限定依赖:

  • MySQL,用于存储配置和节点等相关数据
  • canal版本,要求>=1.1.4 (需要依赖canal-server提供面向admin的动态运维管理接口)

4.1 下载&解压

下载 canal-admin, 访问 release 页面 , 选择需要的包下载, 如以 1.1.4 版本为例

wget https://github.com/alibaba/canal/releases/download/canal-1.1.4/canal.admin-1.1.4.tar.gz

解压缩

mkdir /opt/canal-admin
tar zxvf canal.admin-$version.tar.gz  -C /opt/canal-admin

解压完成后,进入 /opt/canal 目录,可以看到如下结构
在这里插入图片描述
配置修改

vi conf/application.yml

在这里插入图片描述

4.2 初始化

初始化元数据库:
初始化SQL脚本里会默认创建canal_manager的数据库,建议使用root等有超级权限的账号进行初始化 b. canal_manager.sql默认会在conf目录下,也可以通过链接下载 canal_manager.sql
在这里插入图片描述
在这里插入图片描述

4.3 启动&查看

启动

sh bin/startup.sh

查看 admin 日志

vi logs/admin.log

此时代表canal-admin已经启动成功,可以通过 http://127.0.0.1:8089/ 访问,默认密码:admin/123456
在这里插入图片描述
在这里插入图片描述

canal-server端配置

# register ip
canal.register.ip =
# 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 =

启动admin-server即可。
或在启动命令中使用参数:sh bin/startup.sh local 指定配置
just have fun!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值