天天看點

可視化資料同步遷移工具 CloudCanal

可視化資料同步遷移工具 CloudCanal

CloudCanal 核心團隊成員來自阿裡巴巴中間件和資料庫團隊, 長期從事分布式資料庫、資料庫中間件、應用中間件工作。CloudCanal 在 MySQL binlog 解析使用了 Canal 部分代碼,其他均為自主研發,并且對 Canal 部分代碼進行了大量重構,修複諸多問題并優化性能。Canal 在 CloudCanal 中的位置,可以用以下圖檔簡單表示,可見 Canal 代碼在 CloudCanal 産品中隻占很小一部分。

可視化資料同步遷移工具 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。

可視化資料同步遷移工具 CloudCanal

預設自帶的測試資料庫

預設幫添加好了測試的 MySQL 資料源,其中 cloudcanal_test_a (源端)和cloudcanal_test_b (目标端)這兩個庫中已經幫準備好了用于測試的表和資料,可以友善您體驗整個流程。

  • 預設已經添加了一台運作機器,用于執行具體的資料同步任務,是以直接添加資料源即可開始建立同步任務。
  • 遇到需要發送短信的場景,先點選擷取驗證碼,然後輸入短信驗證碼 777777 即可。

在主控端上可以直接以下指令通路 MySQL 容器。

docker exec -it cloudcanal-mysql  mysql -uclougence -h127.1 -p123456      
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal

在另一台機器上啟動新的 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 更新

解壓新版本的 cloudcanal.7z 壓縮包,覆寫原目錄下相同的檔案,然後依次執行以下腳本即可。

sh upgrade.sh
sh startup.sh      

因為資料目錄 sidecar_data 和 console_dat 不會被覆寫,是以資料不會丢失。

添加資料源

進入資料源管理界面,點選添加資料源,可以選擇阿裡雲上的資料源或者自建資料庫。

可視化資料同步遷移工具 CloudCanal

準備資料

使用 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
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal

高可用測試

CloudCanal 社群版自 1.0.3 開始支援使用者添加機器,部署高可用叢集。CloudCanal 高可用叢集包含如下特性:

  • 任務容災自動切換:如果任務所在的機器 crash,在機器上的任務會自動切換到叢集内其他可用的機器上。
  • 任務手動排程:如果一台機器上運作了過多的任務,支援使用者手動排程任務到其他機器上運作。
  • 建立任務時自動配置設定到低負載機器上:建立任務的時候,任務會自動配置設定到綁定叢集下負載較低的機器上。

CloudCanal 中的 Sidecar 容器負責資料同步,Console 容器負責任務的排程以及為提供管理操作。接下來分别模拟 Sidecar 容器和 Console 容器故障時,資料能否依然正常同步。

模拟 Sidecar 容器故障

目前同步任務運作在 Sidecar 容器 172.18.0.2 上。

可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal

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 時間戳回溯位點。

可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal

使用 GTID 模式同步(推薦)

CloudCanal 使用 GTID 模式同步就可以很好地解決 binlog + position 方式同步時主從切換無法同步資料的問題。GTID 的全稱是 global transaction id,表示的是全局事務 ID。

GTID 複制與普通複制最大的差別就是不需要指定二進制檔案名和位置,當一個事務在主庫端執行并送出時,産生 GTID,一同記錄到 binlog 中;binlog 中先記錄 GTID,緊跟着再記錄事務相關的操作。

當發生 MySQL 主從切換時,在備庫上就可以根據 GTID 繼續同步資料。使用 GTID 同步的參數需要在建立任務以後在詳情中修改,在建立任務時先關閉自動啟動任務。

可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
可視化資料同步遷移工具 CloudCanal
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 "異構"線上資料遷移同步