使用canal client-adapter完成mysql到es數據同步教程(包括全量和增量)

本文爲我在學習canal的client-adapter的過程中所記錄下來的一些知識點與操作步驟,雖然canal官方也有對應的文檔但是我在看官方的文檔時感覺官方的wiki有的操作步驟寫的不是很清楚,特此記錄與君共勉!

官方clientAdapter文檔:https://github.com/alibaba/canal/wiki/ClientAdapter
canal的client-adapter是爲了讓用戶能快速的運行canal而開發的一個模塊,通過它可以快速地完成從mysql到其他數據源的數據同步功能,本文將演示adapter中elasticsearch部分功能

環境說明

canal 版本

爲了體驗新功能的特性,這裏採用源碼的方式進行項目的運行。選擇當前master分支的代碼進行本地運行(當前時間爲2019年8月31號

mysql版本

mysql採用的是5.7.19版本,運行於docker內。
其運行腳本爲:

docker pull mysql:5.7.19
docker run -p 3306:3306 -v $PWD/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql5719 -d mysql:5.7.19

canal環境安裝

開啓mysql的bin_log

運行時需要注意確保mysql開啓了bin_log,因爲canal的原理是基於bin_log來實現的。
驗證方法爲:

mysql> show variables like 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+

mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+

如上上面的語句返回的爲ROW和ON,則說明是開啓了bin_log的

如果沒有開啓可以參考canal的wiki,地址爲:https://github.com/alibaba/canal/wiki/AdminGuide

[mysqld]  
log-bin=mysql-bin #添加這一行就ok  
binlog-format=ROW #選擇row模式  
server_id=1 #配置mysql replaction需要定義,不能和canal的slaveId重複  

在docker中可通過進入容器的bash進行配置:

docker exec -it dockermysql bash
echo '[mysqld]' >> /etc/mysql/conf.d/mysql.cnf
echo 'log-bin=mysql-bin' >> /etc/mysql/conf.d/mysql.cnf
echo 'binlog-format=ROW' >> /etc/mysql/conf.d/mysql.cnf
echo 'server-id=123454' >> /etc/mysql/conf.d/mysql.cnf

es安裝

es選擇6.8.1版本,之所以選擇6.8.1版本是因爲這是目前還算比較靠前的es版本,同時也是許多虛擬雲支持的es版本
在這裏測試也採用docker來進行安裝
腳本爲:

docker pull docker.elastic.co/elasticsearch/elasticsearch:6.8.1
docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.8.1

kibana安裝

爲方便看到es的數據,這裏再安裝一個kibana
安裝時同樣安裝在docker內,並讓其link到es的容器內。腳本爲:

docker pull docker.elastic.co/kibana/kibana:6.8.1
docker run --link 41f6e52d3c8b:elasticsearch -p 5601:5601 docker.elastic.co/kibana/kibana:6.8.1

其中上面的41f6e52d3c8b爲elasticsearch的容器id

canal server安裝與運行

canal的運行可以直接參考官方的WIKI,其地址爲:https://github.com/alibaba/canal/wiki/Docker-QuickStart
下載好canal server

docker pull canal/canal-server

再下載canal的運行腳本

wget https://raw.githubusercontent.com/alibaba/canal/master/docker/run.sh 

然後根據條件進行啓動即可,如我這裏的:

run.sh -e canal.instance.master.address=127.0.0.1:3306 \
		 -e canal.destinations=example \
         -e canal.instance.dbUsername=root \
         -e canal.instance.dbPassword=123456 \
         -e canal.instance.connectionCharset=UTF-8 \
         -e canal.instance.tsdb.enable=true \
         -e canal.instance.gtidon=false \
         -e canal.instance.filter.regex=.*\\\..*

canal.instance.filter.regex參數代表mysql 數據解析關注的表,Perl正則表達式.
多個正則之間以逗號(,)分隔,轉義符需要雙斜槓(\)
常見例子:

mysql 數據解析關注的表,Perl正則表達式.
多個正則之間以逗號(,)分隔,轉義符需要雙斜槓(\)
常見例子:

  1. 所有表:.* or .\…
  2. canal schema下所有表: canal\…*
  3. canal下的以canal打頭的表:canal\.canal.*
  4. canal schema下的一張表:canal.test1
  5. 多個規則組合使用:canal\…*,mysql.test1,mysql.test2 (逗號分隔)

環境配置完畢後的驗證

  • mysql檢查3306端口,檢查bin_log是否開啓
  • es檢查9200,9300端口是否開啓
  • kibana檢查5601端口是否開啓
  • canal server檢查11111和11112端口是否開啓,1.1.4版本的會開啓11110端口

如果上面的都沒有問題的話,則環境部分OK了

mysql中創建測試庫和測試表及數據

爲了演示的方便,這裏先將mysql的數據創建好,這裏簡單創建一下:

  1. 建庫
CREATE SCHEMA `test` ;
  1. 建表導數據
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for stu_info
-- ----------------------------
DROP TABLE IF EXISTS `stu_info`;
CREATE TABLE `stu_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1;

-- ----------------------------
-- Records of stu_info
-- ----------------------------
INSERT INTO `stu_info` VALUES ('1', 'aaa', '11', '2019-08-31 03:23:11');
INSERT INTO `stu_info` VALUES ('2', 'bbb', '12', '2019-08-31 04:33:22');
INSERT INTO `stu_info` VALUES ('3', 'ccc', '13', '2019-08-31 05:43:33');

es索引驗證及創建目標索引

  1. 測試可用性
    訪問kibana,輸入查詢語句列出目前系統中的所有索引
GET /_cat/indices

在kibana中驗證是否有索引
2. 創建索引
因爲es連接採用的是rest客戶端,需要先將索引創建好,否則會報錯

put mytest_user
{
        "mappings": {
            "doc": {
                "properties": {
                    "name": {
                        "type": "text"
                    },
                    "age": {
                        "type": "long"
                    },
                    "update_time": {
                        "type": "date"
                    }
                }
            }
        }
}

canal adapter在idea中測試運行

這裏爲了研究canal adapter方便決定在idea中進行運行
首選確保idea中已經導入了canal的源碼

canal maven install

將canal的源碼導入到idea中後,找到manven模塊中有root的那個模塊,然後點擊install進行安裝
也就是下圖中的這個:
在maven中安裝
待安裝完成後,會在對應的項目的target目錄下產生相應的運行包,如果不想在開發工具中運行的話,直接拷貝對應的包即可

canal adapter運行

launcher的application.yml配置

找到canal adapter的模塊,修改application.yml配置文件
主要修改點爲:

  1. 指定canal server的地址,並採用tcp方式進行連接
  2. 配置mysql數據源的連接信息
  3. 開啓esAdapter並配置es的連接信息

我這裏是這樣配置的:

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 
  canalServerHost: 192.168.1.66:11111
  batchSize: 500
  syncBatchSize: 1000
  retries: 0
  timeout:
  accessKey:
  secretKey:
  srcDataSources:
    defaultDS:
      url: jdbc:mysql://192.168.1.66:3306/test?useUnicode=true
      username: root
      password: 123456
  canalAdapters:
  - instance: example # canal instance Name or mq topic name
    groups:
    - groupId: g1
      outerAdapters:
      - name: logger
      - name: es
        hosts: 192.168.1.66:9300 # 127.0.0.1:9200 for rest mode
        properties:
          mode: transport # or rest
          cluster.name: docker-cluster

其中192.168.1.66是運行docker虛擬機的ip地址

es adapter配置

在launcher項目中的配置文件下創建es目錄並加入所需要同步的配置文件即可
如我這裏的mytest_user.yml

dataSourceKey: defaultDS
destination: example
groupId: g1
esMapping:
  _index: mytest_user
  _type: doc
  _id: _id
  upsert: true
#  pk: id
  sql: "SELECT a.id as _id,a.name,a.age,a.update_time from stu_info a"
#  objFields:
#    _labels: array:;
  etlCondition: "where a.update_time>={}"
  commitBatch: 3000

es配置文件

launcher adapter運行

配置完畢後,直接運行launcher這個springBoot項目即可,也就是運行CanalAdapterApplication這個類就可以了
adapter launcher運行
當看日誌提示啓動成功後就代表啓動成功了!

canal測試

當canal adapter啓動完畢後就可以進行測試了
canal除了能實現自動增量同步數據的功能外還具有etl的功能
其同步的實現細節會根據數據量的大小自動採用多線程進行同步,也是採用的遊標的方式進行查詢的,在提高了性能的同時也確保了不容易發生oom,詳見博文:canal源碼解析之esAdapter etl功能

canal全表同步(etl功能,手動觸發)

launcher項目是一個spring boot項目,在其中的rest包下有一個controller類,裏面提供了一些接口,其中一個用於全量同步數據的接口

    /**
     * ETL curl http://127.0.0.1:8081/etl/hbase/mytest_person2.yml -X POST
     *
     * @param type 類型 hbase, es
     * @param task 任務名對應配置文件名 mytest_person2.yml
     * @param params etl where條件參數, 爲空全部導入
     */
    @PostMapping("/etl/{type}/{task}")
    public EtlResult etl(@PathVariable String type, @PathVariable String task,
                         @RequestParam(name = "params", required = false) String params) {
        return etl(type, null, task, params);
    }

類上也有註釋,我們按照註釋的內容發送一個http請求即可

curl http://192.168.1.100:8081/etl/es/mytest_user.yml -X POST

其中192.168.1.100爲我本地電腦的ip,mytest_user.yml爲es目錄下的配置文件
運行後就可以讓mytest_user.yml配置的數據表的所有數據全同步到es中了.
執行etl命令後日志
然後再在kibana中看一下es中的數據:

get mytest_user/_search

{
  "took" : 19,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "mytest_user",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "bbb",
          "age" : 12,
          "update_time" : "2019-08-31T05:43:50+08:00"
        }
      },
      {
        "_index" : "mytest_user",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "aaa",
          "age" : 13,
          "update_time" : "2019-08-30T02:43:41+08:00"
        }
      },
      {
        "_index" : "mytest_user",
        "_type" : "doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "ccc",
          "age" : 11,
          "update_time" : "2019-08-30T05:39:38+08:00"
        }
      }
    ]
  }
}

canal條件同步(etl功能,手動觸發)

如果想執行從某一個時刻的數據同步,在上面的測試URL後加上對應的參數就可以了,其參數由es的配置項決定的,也就是上面配置文件中的etlCondition,比如我這裏寫的where a.update_time>={},而{}之內的就是條件

dataSourceKey: defaultDS
destination: example
groupId: g1
esMapping:
  _index: mytest_user
  _type: doc
  _id: _id
  upsert: true
#  pk: id
  sql: "SELECT a.id as _id,a.name,a.age,a.update_time from stu_info a"
#  objFields:
#    _labels: array:;
  etlCondition: "where a.update_time>={}"
  commitBatch: 3000

那麼如果只想同步stu_info表中update_time爲2019-08-31 00:00:00之後的數據,那麼這裏執行的請求爲:

curl http://192.168.1.11:8081/etl/es/mytest_user.yml -X POST -d “params=2019-08-31 00:00:00”

響應爲:

{"succeeded":true,"resultMessage":"導入ES 數據:3 條"}root@ubuntu:~# curl http://192.168.1.11:8081/etl/es/mytest_user.yml -X POST -d "params=2019-08-31 00:00:00"
{"succeeded":true,"resultMessage":"導入ES 數據:1 條"}root@ubuntu:~# 

這個controller的源碼如下,想要操作其他功能,也可以自行看源碼進行了解:

/**
 * 適配器操作Rest
 *
 * @author rewerma @ 2018-10-20
 * @version 1.0.0
 */
@RestController
public class CommonRest {

    private static Logger                 logger           = LoggerFactory.getLogger(CommonRest.class);

    private static final String           ETL_LOCK_ZK_NODE = "/sync-etl/";

    private ExtensionLoader<OuterAdapter> loader;

    @Resource
    private SyncSwitch                    syncSwitch;
    @Resource
    private EtlLock                       etlLock;

    @Resource
    private AdapterCanalConfig            adapterCanalConfig;

    @PostConstruct
    public void init() {
        loader = ExtensionLoader.getExtensionLoader(OuterAdapter.class);
    }

    /**
     * ETL curl http://127.0.0.1:8081/etl/rdb/oracle1/mytest_user.yml -X POST
     *
     * @param type 類型 hbase, es
     * @param key adapter key
     * @param task 任務名對應配置文件名 mytest_user.yml
     * @param params etl where條件參數, 爲空全部導入
     */
    @PostMapping("/etl/{type}/{key}/{task}")
    public EtlResult etl(@PathVariable String type, @PathVariable String key, @PathVariable String task,
                         @RequestParam(name = "params", required = false) String params) {
        OuterAdapter adapter = loader.getExtension(type, key);
        String destination = adapter.getDestination(task);
        String lockKey = destination == null ? task : destination;

        boolean locked = etlLock.tryLock(ETL_LOCK_ZK_NODE + type + "-" + lockKey);
        if (!locked) {
            EtlResult result = new EtlResult();
            result.setSucceeded(false);
            result.setErrorMessage(task + " 有其他進程正在導入中, 請稍後再試");
            return result;
        }
        try {

            boolean oriSwitchStatus;
            if (destination != null) {
                oriSwitchStatus = syncSwitch.status(destination);
                if (oriSwitchStatus) {
                    syncSwitch.off(destination);
                }
            } else {
                // task可能爲destination,直接鎖task
                oriSwitchStatus = syncSwitch.status(task);
                if (oriSwitchStatus) {
                    syncSwitch.off(task);
                }
            }
            try {
                List<String> paramArray = null;
                if (params != null) {
                    paramArray = Arrays.asList(params.trim().split(";"));
                }
                return adapter.etl(task, paramArray);
            } finally {
                if (destination != null && oriSwitchStatus) {
                    syncSwitch.on(destination);
                } else if (destination == null && oriSwitchStatus) {
                    syncSwitch.on(task);
                }
            }
        } finally {
            etlLock.unlock(ETL_LOCK_ZK_NODE + type + "-" + lockKey);
        }
    }

    /**
     * ETL curl http://127.0.0.1:8081/etl/hbase/mytest_person2.yml -X POST
     *
     * @param type 類型 hbase, es
     * @param task 任務名對應配置文件名 mytest_person2.yml
     * @param params etl where條件參數, 爲空全部導入
     */
    @PostMapping("/etl/{type}/{task}")
    public EtlResult etl(@PathVariable String type, @PathVariable String task,
                         @RequestParam(name = "params", required = false) String params) {
        return etl(type, null, task, params);
    }

    /**
     * 統計總數 curl http://127.0.0.1:8081/count/rdb/oracle1/mytest_user.yml
     *
     * @param type 類型 hbase, es
     * @param key adapter key
     * @param task 任務名對應配置文件名 mytest_person2.yml
     * @return
     */
    @GetMapping("/count/{type}/{key}/{task}")
    public Map<String, Object> count(@PathVariable String type, @PathVariable String key, @PathVariable String task) {
        OuterAdapter adapter = loader.getExtension(type, key);
        return adapter.count(task);
    }

    /**
     * 統計總數 curl http://127.0.0.1:8081/count/hbase/mytest_person2.yml
     *
     * @param type 類型 hbase, es
     * @param task 任務名對應配置文件名 mytest_person2.yml
     * @return
     */
    @GetMapping("/count/{type}/{task}")
    public Map<String, Object> count(@PathVariable String type, @PathVariable String task) {
        return count(type, null, task);
    }

    /**
     * 返回所有實例 curl http://127.0.0.1:8081/destinations
     */
    @GetMapping("/destinations")
    public List<Map<String, String>> destinations() {
        List<Map<String, String>> result = new ArrayList<>();
        Set<String> destinations = adapterCanalConfig.DESTINATIONS;
        for (String destination : destinations) {
            Map<String, String> resMap = new LinkedHashMap<>();
            boolean status = syncSwitch.status(destination);
            String resStatus;
            if (status) {
                resStatus = "on";
            } else {
                resStatus = "off";
            }
            resMap.put("destination", destination);
            resMap.put("status", resStatus);
            result.add(resMap);
        }
        return result;
    }

    /**
     * 實例同步開關 curl http://127.0.0.1:8081/syncSwitch/example/off -X PUT
     *
     * @param destination 實例名稱
     * @param status 開關狀態: off on
     * @return
     */
    @PutMapping("/syncSwitch/{destination}/{status}")
    public Result etl(@PathVariable String destination, @PathVariable String status) {
        if (status.equals("on")) {
            syncSwitch.on(destination);
            logger.info("#Destination: {} sync on", destination);
            return Result.createSuccess("實例: " + destination + " 開啓同步成功");
        } else if (status.equals("off")) {
            syncSwitch.off(destination);
            logger.info("#Destination: {} sync off", destination);
            return Result.createSuccess("實例: " + destination + " 關閉同步成功");
        } else {
            Result result = new Result();
            result.setCode(50000);
            result.setMessage("實例: " + destination + " 操作失敗");
            return result;
        }
    }

    /**
     * 獲取實例開關狀態 curl http://127.0.0.1:8081/syncSwitch/example
     *
     * @param destination 實例名稱
     * @return
     */
    @GetMapping("/syncSwitch/{destination}")
    public Map<String, String> etl(@PathVariable String destination) {
        boolean status = syncSwitch.status(destination);
        String resStatus;
        if (status) {
            resStatus = "on";
        } else {
            resStatus = "off";
        }
        Map<String, String> res = new LinkedHashMap<>();
        res.put("stauts", resStatus);
        return res;
    }
}

增量同步測試(自動觸發)

canal增量同步是通過監聽mysql的bin log進行實現了,那麼當數據表裏的內容有變化時canal client就會從canal server處獲取到監聽的內容
這裏我做幾個測試來對數據進行驗證

  1. 新增記錄

INSERT INTO test.stu_info (id, name, age, update_time) VALUES (‘4’, ‘ddd’, ‘13’, ‘2019-08-31 11:28:11’);

結果:數據插入後,es立即同步過去了

  1. 刪除記錄

DELETE from stu_info where id=4

結果:數據執行了刪除後es中id爲4的數據也立即進行了刪除

  1. 修改記錄

update stu_info set age =23 where id=3

結果:es中id爲3的數據也立即進行了變更

  1. 修改表結構
    新增一列後
    結果:es數據無變化

  2. 修改表結構
    刪除一列後
    結果:es數據無變化

canal admin監控

canal爲了管理和監控的方便也提供了ui界面模塊,其模塊爲canal-admin

導入canal-admin配置庫

找到canal-admin-server模塊資源目錄下的canal_manager.sql,將其導入到mysql中

CREATE DATABASE /*!32312 IF NOT EXISTS*/ `canal_manager` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;

USE `canal_manager`;

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for canal_adapter_config
-- ----------------------------
DROP TABLE IF EXISTS `canal_adapter_config`;
CREATE TABLE `canal_adapter_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `category` varchar(45) NOT NULL,
  `name` varchar(45) NOT NULL,
  `status` varchar(45) DEFAULT NULL,
  `content` text NOT NULL,
  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for canal_cluster
-- ----------------------------
DROP TABLE IF EXISTS `canal_cluster`;
CREATE TABLE `canal_cluster` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(63) NOT NULL,
  `zk_hosts` varchar(255) NOT NULL,
  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for canal_config
-- ----------------------------
DROP TABLE IF EXISTS `canal_config`;
CREATE TABLE `canal_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `cluster_id` bigint(20) DEFAULT NULL,
  `server_id` bigint(20) DEFAULT NULL,
  `name` varchar(45) NOT NULL,
  `status` varchar(45) DEFAULT NULL,
  `content` text NOT NULL,
  `content_md5` varchar(128) NOT NULL,
  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `sid_UNIQUE` (`server_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for canal_instance_config
-- ----------------------------
DROP TABLE IF EXISTS `canal_instance_config`;
CREATE TABLE `canal_instance_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `cluster_id` bigint(20) DEFAULT NULL,
  `server_id` bigint(20) DEFAULT NULL,
  `name` varchar(45) NOT NULL,
  `status` varchar(45) DEFAULT NULL,
  `content` text NOT NULL,
  `content_md5` varchar(128) DEFAULT NULL,
  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for canal_node_server
-- ----------------------------
DROP TABLE IF EXISTS `canal_node_server`;
CREATE TABLE `canal_node_server` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `cluster_id` bigint(20) DEFAULT NULL,
  `name` varchar(63) NOT NULL,
  `ip` varchar(63) NOT NULL,
  `admin_port` int(11) DEFAULT NULL,
  `tcp_port` int(11) DEFAULT NULL,
  `metric_port` int(11) DEFAULT NULL,
  `status` varchar(45) DEFAULT NULL,
  `modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Table structure for canal_user
-- ----------------------------
DROP TABLE IF EXISTS `canal_user`;
CREATE TABLE `canal_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(31) NOT NULL,
  `password` varchar(128) NOT NULL,
  `name` varchar(31) NOT NULL,
  `roles` varchar(31) NOT NULL,
  `introduction` varchar(255) DEFAULT NULL,
  `avatar` varchar(255) DEFAULT NULL,
  `creation_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

SET FOREIGN_KEY_CHECKS = 1;

-- ----------------------------
-- Records of canal_user
-- ----------------------------
BEGIN;
INSERT INTO `canal_user` VALUES (1, 'admin', '6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9', 'Canal Manager', 'admin', NULL, NULL, '2019-07-14 00:05:28');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

上面的腳本將會在mysql中建立一個名爲canal_manager的數據庫,並創建好canal庫的基本數據表

canal-admin-server運行

修改canal-admin-server項目的application.yml,主要修改配置庫的數據源,我這裏的配置如下:

server:
  port: 8089
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

spring.datasource:
  url: jdbc:mysql://192.168.1.61:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8&useSSL=false
  username: root
  password: 123456
  driver-class-name: com.mysql.jdbc.Driver
  hikari:
    maximum-pool-size: 10
    minimum-idle: 1

canal:
  adminUser: admin
  adminPasswd: admin

然後啓動canal-admin-server的項目即可,即運行CanalAdminApplication,如果運行成功,則會開啓8089端口遍可以進行訪問了
如我這裏的:
http://localhost:8089
canal admin登錄頁
默認賬號爲:admin 密碼爲:123456
登錄後再手動添加之前的server節點,遍可對此canal server進行一監控和管理了
canal admin 界面

總結

通過canal client-adapter中esAdapter的實踐瞭解了canal的特性,通過canal可以快速完成mysql到其他數據源的數據同步,並支持全量和增量同步的功能.
同是canal也提供了canal-admin-server作爲ui界面可供用戶對canal進行管理和監控.
本文中爲了方便部署的是單節點的canal,對於canal的高可用其官方也有對應的支持.
再次向阿里大佬致敬!
官方https://github.com/alibaba/canal

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章