Canal是基于MySQL二进制日志的高性能数据同步系统 属于阿里巴巴的一个开源项目,基于java实现,整体已经在很多大型的互联网项目生产环境中使用,包括阿里、美团等都有广泛的应用,是一个非常成熟的数据库同步方案,基础的使用只需要进行简单的配置即可,以提供可靠的低延迟增量数据管道。
官方文档:https://github.com/alibaba/canal/wiki
项目地址:https://github.com/alibaba/canal
下载地址:https://github.com/alibaba/canal/releases
Canal将MySQL数据同步至Elasticsearch是基于MySQL的主从复制原理实现。
1.MySQL主从复制原理
show binary events
。I/O
线程与主服务器的binlog日志建立连接后进行读取,读取的binlog日志写入本地 Relay log
中级日志。SQL
线程读取 Relay log
后在本机执行主服务器的操作记录。2.Canal实现原理
3.C/S架构
Canal为C/S架构,分为Server端和Client端
canal-deployer
,server端部署好以后,可以直接监听mysql binlog,因为server端是把自己模拟成了mysql slave,所以,只能接受数据,没有进行任何逻辑的处理,具体的逻辑处理,需要client端进行处理。canal-adapter
,client可以自动开发或者使用官方提供的canal-adapter,Adapter是可以将canal server端获取的数据转换成几个常用的中间件数据源,现在支持kafka、rocketmq、hbase、elasticsearch,针对这几个中间件的支持,直接配置即可,无需开发。4.Canal Admin
从Canal1.1.4版本以后,阿里巴巴推出了Canal的WEB管理UI,版本必须要>=Canal1.1.4以上才可以部署,canal-admin设计上是为canal提供整体配置管理、节点运维等面向运维的功能,提供相对友好的WebUI操作界面,方便更多用户快速和安全的操作。
1.MySQL8.0.18部署
详见:MySQL8.0.18部署
2.开启binlog日志
注意
必须在/etc/my.cnf文件中开启以下选型
[mysqld]
log-bin=/usr/local/mysql/binlogs/mysql-bin #开启 binlog
binlog-format=ROW #选择 ROW 模式,必须为ROW行模式
server_id=1 #配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
3.创建授权
mysql> create user canal identified by 'Canal@2019!'; #创建canal账户
Query OK, 0 rows affected (0.08 sec)
mysql> grant select,replication slave,replication client on *.* to 'canal'@'%'; #授权canal账户查询和复制权限
Query OK, 0 rows affected (0.02 sec)
mysql> flush privileges; #刷新授权
Query OK, 0 rows affected (0.00 sec)
4.查看binlog是否正确启动
mysql> show variables like 'binlog_format%'; #查看binlog模式
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW |
+---------------+-------+
1 row in set (0.06 sec)
5.创建需要同步的数据库
mysql> create database canal_tsdb character set utf8;
Query OK, 1 row affected, 1 warning (0.04 sec)
mysql> use canal_tsdb;
Database changed
mysql> CREATE TABLE canal_table
( #创建canal_table表,字段为 id age name address
-> id
int(11) NOT NULL,
-> age
int(11) NOT NULL,
-> name
varchar(200) NOT NULL,
-> address
varchar(1000) DEFAULT NULL,
-> PRIMARY KEY (id
)
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Query OK, 0 rows affected, 2 warnings (0.30 sec)
mysql> INSERT INTO canal_tsdb
.canal_table
(id
, age
, name
, address
) VALUES (1, 24, '徐伟亮', '上海市浦东新区');
Query OK, 1 row affected (0.02 sec)
mysql> select * from canal_table;
+----+-----+-----------+-----------------------+
| id | age | name | address |
+----+-----+-----------+-----------------------+
| 1 | 24 | 徐伟亮 | 上海市浦东新区 |
+----+-----+-----------+-----------------------+
1 row in set (0.01 sec)
以下两种方式根据需求选择其一即可
集群部署详见:Elasticsearch7.4集群部署并进行安全认证
单点部署详见:Elasticsearch7.4单点部署并进行安全认证
1.下载并解压
wget https://github.com/alibaba/canal/releases/download/canal-1.1.5-alpha-1/canal.deployer-1.1.5-SNAPSHOT.tar.gz
mkdir /usr/local/canal-deployer
tar xf canal.deployer-1.1.5-SNAPSHOT.tar.gz -C /usr/local/canal-deployer/
2.修改配置文件
vim /usr/local/canal-deployer/conf/example/instance.properties
canal.instance.mysql.slaveId=3 #修改ID,不能和MySQL数据库一致
canal.instance.gtidon=false
canal.instance.master.address=192.168.31.216:8809 #指定mysql数据库地址及端口
canal.instance.master.journal.name=
canal.instance.master.position=
canal.instance.master.timestamp=
canal.instance.master.gtid=
canal.instance.rds.accesskey=
canal.instance.rds.secretkey=
canal.instance.rds.instanceId=
canal.instance.tsdb.enable=true
canal.instance.dbUsername=canal #指定复制账号
canal.instance.dbPassword=Canal@2019! #指定复制密码
canal.instance.connectionCharset = UTF-8 #字符集格式,需要与mysql保持一致
canal.instance.enableDruid=false
canal.instance.filter.regex=.*\\..* #表名监控的正则
canal.instance.filter.black.regex=
canal.mq.topic=example
canal.mq.partition=0
3.启动canal-deployer
因为canal-depaloyer由java开发,所以需要jdk环境,jdk版本需要大于1.5
yum install java-1.8.0-openjdk.x86_64 java-1.8.0-openjdk-devel.x86_64 -y
/usr/local/canal-deployer/bin/startup.sh
4.查看日志及端口
1)查看 server 日志
canal-deployer默认监听三个端口,11110
、11111
、11112
11110
:为admin管理端口11111
:为canal deployer 服务器占用的端口11112
:为指标下拉端口
2)查看 instance 的日志
1.下载并解压
wget https://github.com/alibaba/canal/releases/download/canal-1.1.5-alpha-1/canal.adapter-1.1.5-SNAPSHOT.tar.gz
mkdir /usr/local/canal-adapter
tar xf canal.adapter-1.1.5-SNAPSHOT.tar.gz -C /usr/local/canal-adapter/
2.添加mysql8.0.18连接器
默认canal-adapter的lib中只有mysql5.x版本的连接器
wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar
mv mysql-connector-java-8.0.18.jar /usr/local/canal-adapter/lib/
chmod 777 /usr/local/canal-adapter/lib/mysql-connector-java-8.0.18.jar #权限修改与其它lib库一致
chmod +st /usr/local/canal-adapter/lib/mysql-connector-java-8.0.18.jar
3.修改application.yml
vim /usr/local/canal-adapter/conf/application.yml
server:
port: 8081 #指定canal-adapter监听端口
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss #时间格式
time-zone: GMT+8 #时区
default-property-inclusion: non_null
canal.conf: #canal配置
canalServerHost: 192.168.31.240:11111 #指定canal-deployer服务端监听的地址及端口
batchSize: 500 #每次获取数据的批大小, 单位为K
syncBatchSize: 1000 #每次同步的批数量
retries: 0 #试次数, -1为无限重试,0为失败不再重试
timeout: #同步超时时间, 单位毫秒,如将数据同步es的时,假如由于种种原因导致同时时间超出此值则认为超时
srcDataSources: #源数据库配置
defaultDS: #自定义名称
url: jdbc:mysql://192.168.31.216:8809/canal_tsdb?useUnicode=true #jdbc url,指定数据库的地址及端口,canal_tsdb为mysql上面的苦,useUnicode编码
username: canal #指定数据库账号
password: Canal@2019! #指定数据库密码
canalAdapters: #适配器列表
groups: #分组列表
- groupId: g1 #分组id, 如果适配器为MQ模式将用到该值
outerAdapters: #分组内适配器列表
- name: logger #日志打印适配器
- name: es7 #集群版本,支持 es6 与 es7
hosts: 192.168.31.215:9201,192.168.31.215:9202,192.168.31.215:9203 #elasticsearch集群地址,逗号分隔
properties:
mode: rest #可指定transport模式或者rest模式,rest模式下hosts参数指定端口必须为es对外端口,transport模式下hosts参数指定端口必须为集群通信端口
security.auth: elastic:26tBktGolYCyZD2pPISW #指定elasticsearch集群账号密码
cluster.name: elastic_cluster #指定elasticsearch集群名称
4.修改适配器映射文件
vim /usr/local/canal-adapter/conf/es7/mytest_user.yml
dataSourceKey: defaultDS #指定在application.yml文件中srcDataSources源数据源自定义的名称
destination: example #cannal的instance或者MQ的topic,我们是把数据同步至es,所以不用修改,也用不到此处
groupId: g1 #对应MQ模式下的groupId, 只会同步对应groupId的数据
esMapping: #es中的Mapping设置
_index: canal_tsdb #指定索引名称
_id: _id #指定文档id,_id 此值则由es自动分配文档ID
sql: "select a.id as _id,a.age,a.name,a.address from canal_table a" #sql映射
etlCondition: "where a.c_time>={}" #etl的条件参数
commitBatch: 3000 #提交批大小
在配置完成canal-adapter后还不要着急启动,需要事先在es中定义我们指定的索引以及mapping
打开Kibana界面,找到左侧的“开发工具”,然后进行创建索引及指定Mapping
语法如下:
POST canal_tsdb/_doc
{
"mappings":{
"_doc":{
"properties":{
"age":{
"type":"long"
},
"name":{
"type":"text"
},
"address":{
"type":"text"
}
}
}
}
}
查看创建的索引及Mapping
1.在Canal-adapter机器上启动进程并查看日志
/usr/local/canal-adapter/bin/startup.sh
tail -f /usr/local/canal-adapter/logs/adapter/adapter.log
2.在MySQL再次插入一条数据并查看日志
mysql> INSERT INTO canal_tsdb
.canal_table
(id
, age
, name
, address
) VALUES (2, 24, 'abcops.cn', '上海市浦东新区');
Query OK, 1 row affected (0.01 sec)
3.查看Canal-deployer服务端日志
tail -f /usr/local/canal-deployer/logs/example/meta.log
2019-12-17 15:48:47.457 - clientId:1001 cursor:[mysql-bin.000005,2125,1576568901000,2,] address[192.168.31.216/192.168.31.216:8809]
4.查看Canal-apadter客户端日志
tail -f /usr/local/canal-adapter/logs/adapter/adapter.log
2019-12-17 15:48:47.060 [pool-2-thread-1] INFO c.a.o.canal.client.adapter.logger.LoggerAdapterExample - DML: {"data":[{"id":2,"age":24,"name":"abcops.cn","address":"上海市浦东新区"}],"database":"canal_tsdb","destination":"example","es":1576568901000,"groupId":null,"isDdl":false,"old":null,"pkNames":["id"],"sql":"","table":"canal_table","ts":1576568927060,"type":"INSERT"}
2019-12-17 15:48:47.062 [pool-2-thread-1] DEBUG c.a.o.canal.client.adapter.es.core.service.ESSyncService - DML: {"data":[{"id":2,"age":24,"name":"abcops.cn","address":"上海市浦东新区"}],"database":"canal_tsdb","destination":"example","es":1576568901000,"groupId":null,"isDdl":false,"old":null,"pkNames":["id"],"sql":"","table":"canal_table","ts":1576568927061,"type":"INSERT"}
Affected indexes: canal_tsdb
5.到Kibana中查看文档
6.在MySQL中更新数据
mysql> update canal_table set name='goblogs.cn',address='上海市虹口区' where id=2;
Query OK, 1 row affected (0.06 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from canal_table;
+----+-----+------------+-----------------------+
| id | age | name | address |
+----+-----+------------+-----------------------+
| 1 | 24 | 徐伟亮 | 上海市浦东新区 |
| 2 | 24 | goblogs.cn | 上海市虹口区 |
+----+-----+------------+-----------------------+
2 rows in set (0.00 sec)
然后去Kibana中进行查看文档是否被更新
7.在MySQL中删除数据
mysql> delete from canal_table where id=2;
Query OK, 1 row affected (0.02 sec)
mysql> select * from canal_table;
+----+-----+-----------+-----------------------+
| id | age | name | address |
+----+-----+-----------+-----------------------+
| 1 | 24 | 徐伟亮 | 上海市浦东新区 |
+----+-----+-----------+-----------------------+
1 row in set (0.00 sec)
在Kibana中查看文档是否被删除
注:当数据同步至Elasticsearch后,Elasticsearch就有了对同步来数据的CURD权限
canal-admin的限定依赖:
1.MySQL,用于存储配置和节点等相关数据
2.canal版本,要求>=1.1.4 (需要依赖canal-server提供面向admin的动态运维管理接口)
1.Canal Admin下载并解压
wget https://github.com/alibaba/canal/releases/download/canal-1.1.5-alpha-1/canal.admin-1.1.5-SNAPSHOT.tar.gz
mkdir /usr/local/canal-admin
tar xf canal.admin-1.1.5-SNAPSHOT.tar.gz -C /usr/local/canal-admin
2.修改配置文件
vim /usr/local/canal-admin/conf/application.yml
server:
port: 8089 #Canal Admin监听端口
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss #时间格式
time-zone: GMT+8 #时区
spring.datasource: #数据库信息
address: 192.168.31.216:8809 #指定Canal Admin所使用的数据库地址及端口
database: canal_manager #指定数据库名称
username: cadmin #指定数据库账户
password: Cadmin@2019! #指定数据库密码
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: #Canal UI界面默认账号密码
adminUser: admin
adminPasswd: admin
3.创建数据库及授权用户
在数据库节点上创建canal_manager
数据库,并授权于cadmin用户此库的所有权限
mysql> create database canal_manager character set utf8;
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> create database canal_manager character set utf8;
Query OK, 1 row affected, 1 warning (0.01 sec)
mysql> create user cadmin identified by 'Cadmin@2019!';
Query OK, 0 rows affected (0.21 sec)
mysql> grant all on canal_manager.* to 'cadmin'@'%';
Query OK, 0 rows affected (0.03 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
4.导入SQL至MySQL数据库
mysql -u cadmin -h 192.168.31.216 -P 8809 -p
mysql> use canal_manager;
Database changed
mysql> source /usr/local/canal-admin/conf/canal_manager.sql;
mysql> show tables;
+-------------------------+
| Tables_in_canal_manager |
+-------------------------+
| canal_adapter_config |
| canal_cluster |
| canal_config |
| canal_instance_config |
| canal_node_server |
| canal_user |
+-------------------------+
6 rows in set (0.03 sec)
5.启动Canal Admin
/usr/local/canal-admin/bin/startup.sh
查看日志及监听端口
6.访问Canal Admin UI界面
访问链接:http://192.168.31.240:8089
默认账号密码为:admin/123456
需求:现在需要在MySQL中新建 canal_tab01
、canal_tab02
、canal_03
,这三张表,并将这三张表的数据同步至Elasticsearch
1.在Canal-adapter中创建多个配器映射文件
Canal-adapter客户端操作
touch /usr/local/canal-adapter/conf/es7/{canal_tab01.yml,canal_tab02.yml,canal_tab03.yml}
chmod 777 /usr/local/canal-adapter/conf/es7/canal_tab0*
2.在MySQL数据库中创建对应的表
CREATE TABLE canal_tab01
(
id
int(11) NOT NULL,
age
int(11) NOT NULL,
name
varchar(200) NOT NULL,
address
varchar(1000) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.在canal_tab01-03中插入相应的字段
mysql> INSERT INTO canal_tsdb
.canal_tab01
(id
, age
, name
, address
) VALUES (1, 20, 'abcops.cn', '上海市静安区');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO canal_tsdb
.canal_tab02
(id
, age
, name
, address
) VALUES (1, 21, 'k8sops.cn', '上海市黄浦区');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO canal_tsdb
.canal_tab03
(id
, age
, name
, address
) VALUES (1, 22, 'elk.abcops.cn', '上海市长宁区');
Query OK, 1 row affected (0.01 sec)
4.写入适配器文件
以下只列出 canal_tab01
库的配置,其它库只需要修改 _index索引值,以及 canal_tab01查询表名称即可
cat /usr/local/canal-adapter/conf/es7/canal_tab01.yml
dataSourceKey: defaultDS
destination: example
groupId: g1
esMapping:
_index: canal_tab01 #其它两个配置文件只需要把canal_tab01索引换成canal_tab02和canal_tab03即可
_id: _id
sql: "select a.id as _id,a.age,a.name,a.address from canal_tab01 a" #其它两个配置文件需要把查询的表名称换为对应的即可
etlCondition: "where a.c_time>={}"
commitBatch: 3000
5.在Kibana中创建索引及Mapping
POST canal_tab01/_doc
{
"mappings":{
"_doc":{
"properties":{
"age":{
"type":"long"
},
"name":{
"type":"text"
},
"address":{
"type":"text"
}
}
}
}
}
POST canal_tab02/_doc
{
"mappings":{
"_doc":{
"properties":{
"age":{
"type":"long"
},
"name":{
"type":"text"
},
"address":{
"type":"text"
}
}
}
}
}
POST canal_tab03/_doc
{
"mappings":{
"_doc":{
"properties":{
"age":{
"type":"long"
},
"name":{
"type":"text"
},
"address":{
"type":"text"
}
}
}
}
}
6.重启Canal-adapter
/usr/local/canal-adapter/bin/stop.sh
/usr/local/canal-adapter/bin/startup.sh
7.自行查询Canal-adapter日志是否存在错误信息
8.由于Canal最大的缺点就是无法进行对数据的全量同步,所以我们刚在表里插入的字段也不会同步到ES中
9. 插入新的数据,测试是否同步至Elasticsearch
以下只修改了一下ID后进行插入
mysql> INSERT INTO canal_tsdb
.canal_tab01
(id
, age
, name
, address
) VALUES (2, 20, 'abcops.cn', '上海市静安区');
Query OK, 1 row affected (0.23 sec)
mysql> INSERT INTO canal_tsdb
.canal_tab02
(id
, age
, name
, address
) VALUES (2, 21, 'k8sops.cn', '上海市黄浦区');
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO canal_tsdb
.canal_tab03
(id
, age
, name
, address
) VALUES (2, 22, 'elk.abcops.cn', '上海市长宁区');
Query OK, 1 row affected (0.00 sec)
10.查看Elasticsearch数据是否同步成功
1.修改Canal-adapter配置
vim /usr/local/canal-adapter/conf/application.yml
srcDataSources:
defaultDS:
url: jdbc:mysql://192.168.31.216:8809/canal_tsdb?useUnicode=true
username: canal
password: Canal@2019!
crmdb: #自定义名称,我这里拿做库名来做区分
url: jdbc:mysql://192.168.31.216:8809/crmdb?useUnicode=true #指定JDBC URI
username: canal #指定复制账号
password: Canal@2019! #复制密码
增加下图部分
2.创建适配器文件
vim /usr/local/canal-adapter/conf/es7/crmdb_tab01.yml #crmdb库中的第一张表,按照表名称创建文件
dataSourceKey: crmdb #数据源key需要与上面修改的配置自定义名称一致
destination: example
groupId: g1
esMapping:
_index: crmdb_tab01 #一张表一个索引,索引名称按照表名来命名
_id: _id
sql: "select a.id as _id,a.age,a.name,a.address from crmdb_tab01 a" #表名映射sql
etlCondition: "where a.c_time>={}"
commitBatch: 3000
3.创建库和表
创建crmdb
库这里略过,创建crmdb_tab01
表也略过
4.在Kibana中创建索引及Mapping
创建索引要与适配器文件中的索引名称一致,字段类型要与MySQL中符合,如果忘记请看上面文章,自行创建
5.重启Canal-adapter
/usr/local/canal-adapter/bin/stop.sh
/usr/local/canal-adapter/bin/startup.sh
6.在crmdb库中的crmdb_tab01表中自行插入数据
过程略。。。
7.查看canal-adapter日志
过程略
8.在Kibana中查看索引及同步来的文档
缺点: