CloudCanal 核心團隊成員來自阿裡巴巴中間件和資料庫團隊, 長期從事分布式資料庫、資料庫中間件、應用中間件工作。CloudCanal 在 MySQL binlog 解析使用了 Canal 部分代碼,其他均為自主研發,并且對 Canal 部分代碼進行了大量重構,修複諸多問題并優化性能。Canal 在 CloudCanal 中的位置,可以用以下圖檔簡單表示,可見 Canal 代碼在 CloudCanal 産品中隻占很小一部分。
CloudCanal 高可用部署
準備工作
安裝 Docker
不同作業系統可以參考 Docker 官網文檔 進行安裝。
安裝 Docker Compose
這裡提供一個國内的鏡像站的安裝指令,也可以參考 Docker-Compose 安裝文檔。
curl -L https://get.daocloud.io/docker/compose/releases/download/1.28.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
安裝 7z
收到的安裝包為 cloudcanal.7z,其中包含了鏡像和管理腳本。需要通過安裝和使用 7z 指令進行解壓。
### 安裝7z指令(centos系)
sudo yum install p7zip p7zip-plugins
### 安裝7z指令(ubuntu系)
sudo apt-get install p7zip-full p7zip-rar
### 安裝7z指令(macOS)
brew install 7z
### 進到安裝包所在路徑,執行以下指令進行解壓縮
7z x cloudcanal.7z
如果無法通過 yum 或者 apt 等源直接安裝,可以通過編譯的方式安裝。
wget http://nchc.dl.sourceforge.net/sourceforge/p7zip/p7zip_4.65_src_all.tar.bz2
tar -xjvf p7zip_4.65_src_all.tar.bz2
cd p7zip_4.65
make
make install
然後使用 7za 指令解壓。
7za x cloudcanal.7z
解壓後目錄如下,主要分為三大塊:
- 鏡像:包含四個 tar 壓縮檔案。
- 腳本:啟動、更新和停止,以及 scripts 運維腳本目錄。
- 日志與配置檔案:日志為 docker-compose 啟動日志,配置檔案為 docker-compose 配置檔案。
[root@master1 chengzw]# ls -l cloudcanal
總用量 2939372
-rw------- 1 root awx 912166912 8月 31 19:34 console.tar
-rw-r--r-- 1 root awx 12211728 8月 31 15:27 docker-compose
-rw-r--r-- 1 root awx 320 8月 31 19:29 docker-compose-sidecar.yml
-rw-r--r-- 1 root awx 1418 8月 31 19:29 docker-compose.yml
-rw------- 1 root awx 453986816 8月 31 19:32 mysql.tar
-rw------- 1 root awx 190344192 8月 31 19:37 prometheus.tar
drwxr-xr-x 2 root awx 180 8月 31 19:29 scripts
-rwxr-xr-x 1 root awx 63 8月 31 19:29 shutdown.sh
-rw------- 1 root awx 1441171968 8月 31 19:37 sidecar.tar
-rwxr-xr-x 1 root awx 1211 8月 31 19:29 startNewSidecar.sh
-rwxr-xr-x 1 root awx 2682 8月 31 19:29 startup.sh
-rwxr-xr-x 1 root awx 2031 8月 31 19:29 upgrade.sh
-rw-r--r-- 1 root awx 376 8月 31 19:29 使用必讀.txt
啟動 CloudCanal
在解壓的路徑下可以執行以下指令啟動 CloudCanal。
sh startup.sh
當終端出現 cloudcanal start 時,表示啟動成功。可以通路 http://${部署機器ip}:8111 來登入 CloudCanal。
預設自帶的測試資料庫
預設幫添加好了測試的 MySQL 資料源,其中 cloudcanal_test_a (源端)和cloudcanal_test_b (目标端)這兩個庫中已經幫準備好了用于測試的表和資料,可以友善您體驗整個流程。
- 預設已經添加了一台運作機器,用于執行具體的資料同步任務,是以直接添加資料源即可開始建立同步任務。
- 遇到需要發送短信的場景,先點選擷取驗證碼,然後輸入短信驗證碼 777777 即可。
在主控端上可以直接以下指令通路 MySQL 容器。
docker exec -it cloudcanal-mysql mysql -uclougence -h127.1 -p123456
在另一台機器上啟動新的 Sidecar 容器
首先将 CloudCanal 的安裝包在待部署的新機器上解壓。在安裝包目錄下,執行如下指令添加一台新的 Sidecar 容器。注意在一台機器上不允許啟動兩個 Sidecar 容器,請在新的機器上啟動 Sidecar 容器。
sh startNewSidecar.sh
複制機器唯一辨別到容器内指定配置檔案内。先進入 Sidecar 容器。
docker exec -it cloudcanal-sidecar /bin/bash
在 Sidecar 容器内修改配置檔案:vi /home/clougence/cloudcanal/global_conf/conf.properties。
cloudcanal.auth.ak=ak0a2c62tdo1ap2416655mpyx0v36l359p1v5rn782caw8t0qkk1s94b80lfs90
cloudcanal.auth.sk=sk6206iy4pb0eydz9hg97jo3tu5d80j97e91bbql65167u8wb75x4ej6e4v4aa4
cloudcanal.sidecar.wsn=wsnd0ndmrhsm9yu9lj06897h4cvh42br0s5c1e4iut0e93g78as46t7oe5k04fi3
# 替換 cloudcanal.console.domain 的值為 console 容器所在主控端的内網ip
cloudcanal.console.domain=11.8.36.104
修改完成後,修改目錄權限:
chown -R clougence:clougence /home/clougence/cloudcanal
然後切換到 clougence 使用者啟動 Sidecar 程序。
sh /home/clougence/cloudcanal/sidecar/bin/startSidecar.sh
## 檢視日志,确認是否有異常。如果都為INFO或者WARN日志就是正常的
tail -f /home/clougence/logs/cloudcanal/sidecar/sidecar.log
在控制台界面可以看到機器成功注冊。
CloudCanal 更新
解壓新版本的 cloudcanal.7z 壓縮包,覆寫原目錄下相同的檔案,然後依次執行以下腳本即可。
sh upgrade.sh
sh startup.sh
因為資料目錄 sidecar_data 和 console_dat 不會被覆寫,是以資料不會丢失。
添加資料源
進入資料源管理界面,點選添加資料源,可以選擇阿裡雲上的資料源或者自建資料庫。
準備資料
使用 Percona 公司提供工具來随機生成資料,github 位址:
https://github.com/Percona-Lab/mysql_random_data_load/releases。
執行以下指令下載下傳并解壓工具。
wget https://github.com/Percona-Lab/mysql_random_data_load/releases/download/v0.1.12/mysql_random_data_load_0.1.12_Linux_x86_64.tar.gz
tar -xzvf mysql_random_data_load_0.1.12_Linux_x86_64.tar.gz
在源庫建立一張表:
CREATE TABLE `acpcanaldb`.`t7` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tcol01` tinyint(4) DEFAULT NULL,
`tcol02` smallint(6) DEFAULT NULL,
`tcol03` mediumint(9) DEFAULT NULL,
`tcol04` int(11) DEFAULT NULL,
`tcol05` bigint(20) DEFAULT NULL,
`tcol06` float DEFAULT NULL,
`tcol07` double DEFAULT NULL,
`tcol08` decimal(10,2) DEFAULT NULL,
`tcol09` date DEFAULT NULL,
`tcol10` datetime DEFAULT NULL,
`tcol11` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`tcol12` time DEFAULT NULL,
`tcol13` year(4) DEFAULT NULL,
`tcol14` varchar(100) DEFAULT NULL,
`tcol15` char(2) DEFAULT NULL,
`tcol16` blob,
`tcol17` text,
`tcol18` mediumtext,
`tcol19` mediumblob,
`tcol20` longblob,
`tcol21` longtext,
`tcol22` mediumtext,
`tcol23` varchar(3) DEFAULT NULL,
`tcol24` varbinary(10) DEFAULT NULL,
`tcol25` enum('a','b','c') DEFAULT NULL,
`tcol26` set('red','green','blue') DEFAULT NULL,
`tcol27` float(5,3) DEFAULT NULL,
`tcol28` double(4,2) DEFAULT NULL,
`tcol29` varchar(5000) DEFAULT NULL,
`tcol30` varchar(5000) DEFAULT NULL,
`tcol31` varchar(5000) DEFAULT NULL,
`tcol32` blob,
`tcol33` blob,
`tcol34` blob,
`tcol35` blob,
`tcol36` blob,
`tcol37` blob,
`tcol38` blob,
`tcol39` blob,
`tcol40` blob,
`tcol41` blob,
`tcol42` blob,
`tcol43` blob,
`tcol44` blob,
`tcol45` blob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
使用工具持續往源庫插入 1000w 條資料。
./mysql_random_data_load acpcanaldb t7 10000000 \
--host 11.17.6.185 --port 4679 \
--user=acpcanaldb --password=xxxxxx
資料同步
全量同步 + 增量同步
進入任務管理頁面,點選建立任務。選擇源執行個體和目标執行個體,指定資料庫映射關系。
高可用測試
CloudCanal 社群版自 1.0.3 開始支援使用者添加機器,部署高可用叢集。CloudCanal 高可用叢集包含如下特性:
- 任務容災自動切換:如果任務所在的機器 crash,在機器上的任務會自動切換到叢集内其他可用的機器上。
- 任務手動排程:如果一台機器上運作了過多的任務,支援使用者手動排程任務到其他機器上運作。
- 建立任務時自動配置設定到低負載機器上:建立任務的時候,任務會自動配置設定到綁定叢集下負載較低的機器上。
CloudCanal 中的 Sidecar 容器負責資料同步,Console 容器負責任務的排程以及為提供管理操作。接下來分别模拟 Sidecar 容器和 Console 容器故障時,資料能否依然正常同步。
模拟 Sidecar 容器故障
目前同步任務運作在 Sidecar 容器 172.18.0.2 上。
MySQL 主從切換
通常在生産環境中,我們通常會部署雙主模式的 MySQL,通過 keepalived 對外提供一個虛拟 IP,當主庫發生故障時,虛拟 IP 漂移到備庫上,由備庫接管服務。關于MySQL 雙主高可用部署可以參考
MySQL + Keepalived 雙主熱備搭建CloudCanal 使用 binlog + position 進行同步
CloudCanal 預設建立的同步任務是是基于 binlog 和 position 的方式同步的,當 MySQL 發生主從切換時,由于 MySQL 主從的 binlog 檔案是不一緻的,是以 MySQL 切換後 CloudCanal 基于 binlog + position 的方式無法正常同步資料。
如果想在 MySQL 主從切換後 CloudCanal 可以正常同步資料,需要重新指定 CloudCanal 的位點。先停止 CloudCanal,然後根據 binlog 時間戳回溯位點。
使用 GTID 模式同步(推薦)
CloudCanal 使用 GTID 模式同步就可以很好地解決 binlog + position 方式同步時主從切換無法同步資料的問題。GTID 的全稱是 global transaction id,表示的是全局事務 ID。
GTID 複制與普通複制最大的差別就是不需要指定二進制檔案名和位置,當一個事務在主庫端執行并送出時,産生 GTID,一同記錄到 binlog 中;binlog 中先記錄 GTID,緊跟着再記錄事務相關的操作。
當發生 MySQL 主從切換時,在備庫上就可以根據 GTID 繼續同步資料。使用 GTID 同步的參數需要在建立任務以後在詳情中修改,在建立任務時先關閉自動啟動任務。
GET student/_search
#傳回結果
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "student",
"_type" : "_doc",
"_id" : "5",
"_score" : 1.0,
"_source" : {
"name" : "marry",
"id" : 5,
"age" : 19
}
},
{
"_index" : "student",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "jack",
"id" : 2,
"age" : 18
}
},
{
"_index" : "student",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"name" : "mike",
"id" : 3,
"age" : 20
}
},
{
"_index" : "student",
"_type" : "_doc",
"_id" : "4",
"_score" : 1.0,
"_source" : {
"name" : "cris",
"id" : 4,
"age" : 18
}
},
{
"_index" : "student",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "tom",
"id" : 1,
"age" : 18
}
}
]
}
}
往 MySQL 中再插入 1 條資料。
insert into acpcanaldb.student (name,age) values ('peter',20);
在 Elasticsearch 中也可以查到剛剛删除的資料。
GET student/_search
{
"query": {
"match": {
"name": "peter"
}
}
}
#傳回結果
{
"took" : 732,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.6931471,
"hits" : [
{
"_index" : "student",
"_type" : "_doc",
"_id" : "6",
"_score" : 0.6931471,
"_source" : {
"name" : "peter",
"id" : 6,
"age" : 20
}
}
]
}
}
在 MySQL 中删除 age 為 18 的記錄。
[email protected] acpcanaldb 01:35:10>select * from acpcanaldb.student;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 1 | tom | 18 |
| 2 | jack | 18 |
| 3 | mike | 20 |
| 4 | cris | 18 |
| 5 | marry | 19 |
| 6 | peter | 20 |
+----+-------+------+
6 rows in set (0.01 sec)
[email protected] acpcanaldb 01:36:16>delete from acpcanaldb.student where age=18;
Query OK, 3 rows affected (0.02 sec)
[email protected] acpcanaldb 01:36:27>select * from acpcanaldb.student;
+----+-------+------+
| id | name | age |
+----+-------+------+
| 3 | mike | 20 |
| 5 | marry | 19 |
| 6 | peter | 20 |
+----+-------+------+
3 rows in set (0.01 sec)
在 Elasticsearch 上此時也已經删除了對應的資料。
GET student/_search
{
"query": {
"match": {
"age": 18
}
}
}
#傳回結果
{
"took" : 710,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
在 MySQL 中修改表結構。
[email protected] acpcanaldb 01:38:49>update acpcanaldb.student set location='china';
Query OK, 3 rows affected (0.02 sec)
Rows matched: 3 Changed: 3 Warnings: 0
[email protected] acpcanaldb 01:39:25>select * from acpcanaldb.student;
+----+-------+------+----------+
| id | name | age | location |
+----+-------+------+----------+
| 3 | mike | 20 | china |
| 5 | marry | 19 | china |
| 6 | peter | 20 | china |
+----+-------+------+----------+
3 rows in set (0.01 sec)
Elasticsearch 并不會修改對應的 mapping。
GET student/_mapping
#傳回結果
{
"student" : {
"mappings" : {
"properties" : {
"age" : {
"type" : "integer"
},
"id" : {
"type" : "integer"
},
"name" : {
"type" : "text",
"analyzer" : "standard"
}
}
}
}
}
參考資料
- CloudCanal和Canal的差別
- CloudCanal社群版高可用部署教程
- CloudCanal社群版docker版安裝(Linux/MacOS)
- 5分鐘搞定 MySQL 到 MySQL "異構"線上資料遷移同步