之前寫過一篇介紹 canal 的文章《mysql增量同步 - canal》,在資料同步的部分,主要著重演示了在程式碼中通過 canal.client
來同步。當時也有提到 canal adapter
,但並未詳述。最近愈多地接觸 elasticsearch 專案的開發,趁著假期試著做了個Demo,順便記下筆記。
1. canal 介紹
1.1. 三兄弟簡介
canal 對應包的下載和安裝的教程,都直接看 canal官方github,安裝包目前有三兄弟:
- canal deployer:又稱 canal server,是真正監聽 mysql 日誌的服務端。
- canal adapter:顧名思義“介面卡”,搭配 canal server,目前能實現mysql 資料到 hbase、rdb、es的增量同步,妥妥的 ETL 工具。
- canal admin:也是為 canal server 服務的,為canal提供整體配置管理、節點運維等面向運維的功能,提供相對友好的WebUI操作介面。如果 canal server 要搭建叢集環境,必少不了 canal admin 這樣專業的運維工具。
對於不太逛github的人,把文件也貼上:
1.2. canal adapter
它既然是介面卡,那麼就得介紹“源頭”和“目標”這兩個部位資料的對接:
- 源頭:(1)canal adapter 可以直連 canal server ,消費 instance的資料;(2)也可以在讓 canal server 將資料投遞到 MQ,然後 cancal adapter 消費 MQ 中的資料。
- 目標:目前支援 hbase、rdb、es,後續將支援 mongodb、redis等。
本文實現的較簡單,資料流向包括:mysql -> canal server -> canal adapter -> es
。
2. 資料準備
2.1. mysql 建表
開啟 binlog 日誌的部分檢視之前的文章。準備兩張表:
-- 員工表
CREATE TABLE `hr_user` (
`id` char(32) NOT NULL COMMENT '主鍵',
`username` varchar(50) DEFAULT NULL COMMENT '賬號',
`fullname` varchar(50) DEFAULT NULL COMMENT '姓名',
`sex` tinyint DEFAULT NULL COMMENT '性別 0-男/1-女',
`birthday` date DEFAULT NULL COMMENT '生日',
`dept_id` char(32) DEFAULT NULL COMMENT '所屬部門ID',
`deleted` tinyint DEFAULT NULL COMMENT '是否已刪除 0-否/1-是',
`created_by` char(32) DEFAULT NULL COMMENT '建立人ID',
`create_time` datetime DEFAULT NULL COMMENT '建立時間',
`updated_by` char(32) DEFAULT NULL COMMENT '更新人ID',
`updated_time` datetime DEFAULT NULL COMMENT '更新時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 部門表
CREATE TABLE `hr_dept` (
`id` char(32) NOT NULL COMMENT '主鍵',
`dept_name` varchar(50) DEFAULT NULL COMMENT '部門名稱',
`manager_name` varchar(50) DEFAULT NULL COMMENT '部門經理姓名',
`parent_id` char(32) DEFAULT NULL COMMENT '父級部門ID',
`dept_path` varchar(1000) DEFAULT NULL COMMENT '部門路徑',
`deleted` tinyint DEFAULT NULL COMMENT '是否已刪除 0-否/1-是',
`created_by` char(32) DEFAULT NULL COMMENT '建立人ID',
`create_time` datetime DEFAULT NULL COMMENT '建立時間',
`updated_by` char(32) DEFAULT NULL COMMENT '更新人ID',
`updated_time` datetime DEFAULT NULL COMMENT '更新時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.2. 安裝 es、kibana
es docker shell
docker run -d \
--name elasticsearch \
--restart=on-failure:3 \
-p 9200:9200 \
-p 9300:9300 \
-e "discovery.type=single-node" \
-v /Volumes/elasticsearch/data/:/usr/share/elasticsearch/data/ \
-v /Volumes/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /Volumes/elasticsearch/plugins/:/usr/share/elasticsearch/plugins/ \
elasticsearch:7.9.3
kibana docker shell
docker run -d \
--name kibana \
--link elasticsearch:es \
-p 5601:5601 \
-e ELASTICSEARCH_URL=es:9200 \
kibana:7.9.3
2.3. 建立索引
在 kibana -> Management -> Dev Tools 執行建立索引 user:
PUT user
{
"mappings":{
"properties":{
"birthday":{
"type":"date",
"format":"yyyy-MM-dd"
},
"dept_id":{
"type":"keyword"
},
"dept_name":{
"type":"text",
"analyzer":"ik_max_word"
},
"dept_updated_time":{
"type":"date"
},
"fullname":{
"type":"text",
"analyzer":"ik_max_word"
},
"sex":{
"type":"byte"
},
"user_id":{
"type":"keyword"
},
"user_updated_time":{
"type":"date"
},
"username":{
"type":"text"
}
}
}
}
3. canal 配置
目前最新的 release 版本是 1.1.6-alpha-1
,這裡都只下載該版本的 canal-deployer 、canal-adapter 兩個壓縮包,在本地解壓下來各自對應一個目錄。canal-admin 就不安裝了,前面兩個暫時就夠用了。
3.1. canal server
canal server 的安裝配置其實 《mysql增量同步 - canal》 文章中就有了,還是簡單列一下。
因為不做 canal server 將資料投遞到 MQ,所以關注conf/example/instance.properties 的下面引數即可:
canal.instance.master.address = 127.0.0.1:3306
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal
配置裡面預設啟動的是叫 example 的 instance,所以啟動指令碼和檢視日誌對應下面:
# 啟動
sh bin/startup.sh
# 關閉
sh bin/stop.sh
# 檢視具體例項日誌
tail -500f logs/example/example.log
3.2. canal adapter
所有 adapter 的配置參考 adapter同步es的wiki
1. 修改 conf/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:
mode: tcp #tcp kafka rocketMQ rabbitMQ
flatMessage: true
zookeeperHosts:
syncBatchSize: 1000
retries: 0
timeout:
accessKey:
secretKey:
consumerProperties:
# canal tcp consumer
canal.tcp.server.host: 127.0.0.1:11111
canal.tcp.zookeeper.hosts:
canal.tcp.batch.size: 500
canal.tcp.username:
canal.tcp.password:
srcDataSources:
defaultDS:
url: jdbc:mysql://127.0.0.1:3306/es?useUnicode=true
username: canal
password: canal
canalAdapters:
- instance: example
groups:
- groupId: g1
outerAdapters:
- name: es7
hosts: http://127.0.0.1:9200
properties:
mode: rest
cluster.name: docker-cluster
因為是直連 canal server,所以 mode: tcp
,沒有選擇其他 mq。其他的就是配置 canal server、mysql、es 的連線資訊。
2. 新增 conf/es7/user.yml
因為需要做 mysql 往 es中 user 索引的同步,就在 es7中新增一個 user.yml 檔案,因為前面 conf/application.yml 中配置了介面卡載入路徑 es7
,所以預設會載入這個目錄下所有 yml 檔案。
user.yml
dataSourceKey: defaultDS
destination: example
groupId: g1
esMapping:
_index: user
_id: user_id
sql: "SELECT
u.id AS user_id,
u.username,
u.fullname,
u.sex,
u.birthday,
u.dept_id,
d.dept_name,
u.updated_time as user_updated_time,
d.updated_time as dept_updated_time
FROM
hr_user u
LEFT JOIN
hr_dept d ON u.dept_id = d.id"
etlCondition: "where u.deleted = 0 AND d.deleted = 0"
commitBatch: 3000
還是比較一目瞭然的,配置了往 es 中 user 索引同步的資料來源sql。不過是有一定規範要求的,具體規範要求,還是要看前面發的官方wiki文件。
3. 啟動
# 啟動
sh bin/startup.sh
# 關閉
sh bin/stop.sh
# 檢視介面卡日誌
tail -500f logs/adapter/adapter.log
如果能看到 canal server、canal adapter 的日誌都沒報錯資訊,那就可以了。
4. 驗證
為了方便檢視 es 中的資料,在 kibana 中將 user索引新增到 Discover
中。在 Kibana -> Management -> Stack Management -> Kibana -> Index patterns -> Create index pattern
,新增 user索引。然後回到 Discover
就能看到對應索引中的資料了。
在 mysql 中對應表中各自新增一條資料:
-- hr_dept
INSERT INTO hr_dept (id,dept_name,manager_name,parent_id,dept_path,deleted,created_by,create_time,updated_by,updated_time)
VALUES ('9ef57211ca3311ec8fe00242ac110004','中臺研發部','羅永浩','66ab59dbcabf11ec8fe00242ac110004','研發中心>平臺架構部>TPaaS研發部',0,NULL,now(),NULL,now());
-- hr_user
INSERT INTO hr_user (id,username,fullname,sex,birthday,dept_id,deleted,created_by,create_time,updated_by,updated_time)
VALUES ('b7205315cac811ec8fe00242ac110004','zhangsan','張三',0,'1995-02-18','9ef57211ca3311ec8fe00242ac110004',0,NULL,now(),NULL,now());
在 kibana 中就能看到對應 es索引中也新增了一條資料,對應的日誌在 canal adapter adapter.log 日誌中也能看到。
然後無論我們單獨修改 hr_user 表,還是隻是修改了 hr_dept 表中的 dept_name
欄位,es 中對應那條的文件也會隨之修改。