一、canal的程序入口
在官網給的GitHub裏面的deployer模塊裏面,官網:https://github.com/alibaba/canal/tree/master/deployer
其中的main方法在:com.alibaba.otter.canal.deployer.CanalLauncher類裏面
二、加載canal的全局配置文件
追蹤源碼發現canal加載配置文件有兩種方法:一種加載的是本地的./conf/canal.properties;另一種是加載一個指定數據庫的某個字段的值。第一種:稱爲本地加載,第二種是遠程加載。
1、本地加載(默認加載方式)
官網的簡易教程就是本地加載的方式:https://github.com/alibaba/canal
2、遠程加載
遠程加載的配置內容是在一個canal_manager的數據庫裏面,裏面有canal_config、canal_instance_config表
(1)、配置遠程加載的數據庫的信息,修改./conf/canal.properties文件裏面的前三行(加載了遠程配置文件的就會覆蓋本地的)
canal.manager.jdbc.url=jdbc:mysql://127.0.0.1:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8
canal.manager.jdbc.username=root
canal.manager.jdbc.password=121212
改成自己的數據庫,用戶和密碼(去掉備註),默認數據庫是canal_manager
(2)、創建遠程數據庫和表
create database if not EXISTS canal_manager;
create table if not EXISTS canal_manager.canal_config(
id BIGINT,
name VARCHAR(20),
content LONGTEXT,
modified_time TIMESTAMP
);
create table if not EXISTS canal_manager.canal_instance_config(
id BIGINT,
name VARCHAR(20),
content LONGTEXT,
modified_time TIMESTAMP
);
其中canal_config裏面的content值就是canal.properties的內容,並且這個表的數據只能有一行,id必須是1
其中canal_instance_config裏面的content的值是instance.properties的內容,instance的個數就是數據的行數,也就是每一行對應一個instance。這樣在數據庫裏面修改content的值就可以實現動態的遠程的加載配置文件。(配置的這個數據庫服務和同步的數據庫服務不是一個,ip不一樣)
三、官網給的配置方式
1、canal配置方式有兩種:
- ManagerCanalInstanceGenerator: 基於manager管理的配置方式,目前alibaba內部配置使用這種方式。大家可以實現CanalConfigClient,連接各自的管理系統,即可完成接入。
- SpringCanalInstanceGenerator:基於本地spring xml的配置方式,目前開源版本已經自帶該功能所有代碼,建議使用
針對於以上兩種方式:網上更多的是第二種,目前沒有看到任何關於第一種manager的配置,以下是個人對於manager的配置。
2、manager配置
這個過程需要修改源碼,準備工作需要先把官網的源碼下載到本地,源碼clone地址:https://github.com/alibaba/canal.git
(1)、修改canal.properties文件
canal.instance.global.mode = manager
canal.instance.global.lazy = false
(2)、重寫com.alibaba.otter.canal.instance.manager.CanalConfigClient類(在instance裏面)
public class CanalConfigClient {
/**
* 根據對應的destinantion查詢Canal信息
*/
public Canal findCanal(String destination) {
// TODO 根據自己的業務實現
//獲取Apollo的配置
System.setProperty("app.id","canal");
System.setProperty("apollo.cluster","default");
System.setProperty("apollo.meta","http://*.*.*.*:8080,http://*.*.*.*:8080");
Config config = ConfigService.getConfig(destination+".properties"); //config instance is singleton for each namespace and is never null
Long slaveId = Long.parseLong(config.getProperty("canal.instance.mysql.slaveId", "123456"));
String USERNAME = config.getProperty("canal.instance.dbUsername", "canal");
String PASSWORD = config.getProperty("canal.instance.dbPassword", "canal");
String MYSQL_ADDRESS = config.getProperty("canal.instance.master.address", "*.*.*.*:3306").split(":")[0];
int port = Integer.parseInt(config.getProperty("canal.instance.master.address", "*.*.*.*:3306").split(":")[1]);
Canal canal = new Canal();
canal.setId(1L);
canal.setName(destination);
canal.setDesc("test");
CanalParameter parameter = new CanalParameter();
parameter.setZkClusters(Arrays.asList("127.0.0.1:2188"));
parameter.setMetaMode(CanalParameter.MetaMode.MEMORY);
parameter.setHaMode(CanalParameter.HAMode.HEARTBEAT);
parameter.setIndexMode(CanalParameter.IndexMode.MEMORY);
parameter.setStorageMode(CanalParameter.StorageMode.MEMORY);
parameter.setMemoryStorageBufferSize(32 * 1024);
parameter.setSourcingType(CanalParameter.SourcingType.MYSQL);
parameter.setDbAddresses(Arrays.asList(new InetSocketAddress(MYSQL_ADDRESS, 3306),
new InetSocketAddress(MYSQL_ADDRESS, 3306)));
parameter.setDbUsername(USERNAME);
parameter.setDbPassword(PASSWORD);
//parameter.setPositions(Arrays.asList("{\"journalName\":\"mysql-bin.000001\",\"position\":6163L,\"timestamp\":1322803601000L}",
// "{\"journalName\":\"mysql-bin.000001\",\"position\":6163L,\"timestamp\":1322803601000L}"));
System.out.println(USERNAME+PASSWORD);
parameter.setSlaveId(1234L);
parameter.setDefaultConnectionTimeoutInSeconds(30);
parameter.setConnectionCharset("UTF-8");
parameter.setConnectionCharsetNumber((byte) 33);
parameter.setReceiveBufferSize(8 * 1024);
parameter.setSendBufferSize(8 * 1024);
parameter.setDetectingEnable(false);
parameter.setDetectingIntervalInSeconds(10);
parameter.setDetectingRetryTimes(3);
//parameter.setDetectingSQL(DETECTING_SQL);
canal.setCanalParameter(parameter);
/* System.out.println(username+password+host+port);
CanalParameter canalParameter = new CanalParameter();
canalParameter.setSlaveId(slaveId);
canalParameter.setDbUsername(username);
canalParameter.setDbPassword(password);
canalParameter.setIndexMode(CanalParameter.IndexMode.MEMORY);
List<InetSocketAddress> dbAddresses = new ArrayList<>();
dbAddresses.add(new InetSocketAddress(host,port));
canalParameter.setDbAddresses(dbAddresses);
canal.setCanalParameter(canalParameter);
canal.setName(destination);*/
return canal;
}
/**
* 根據對應的destinantion查詢filter信息
*/
public String findFilter(String destination) {
// TODO 根據自己的業務實現
Config config = ConfigService.getConfig(destination+".properties");
return config.getProperty("canal.instance.filter.regex",".*\\..*");
}
}
這兩個方法的實現比較簡單,但是在運行不成功,可能官網給的源碼的關於manager的不是太全,畢竟阿里自己用的是manager配置文件的方式。官網也推薦使用spring的方式,自己修改源碼,用manager的方式總是會有意想不到的問題(也可能自己解讀源碼不全)。
四、總結
對於canal來說配置文件有兩部分,一個是:全局的canal.properties(也可以說是canal-server配置),另一個是:instance.properties(也可以說是canal-client配置,也即instance配置)
總的來說有四種加載配置文件的方式:
1、本地加載+spring:默認加載../conf下的所有配置文件,canal.instance.global.mode = spring
2、本地加載+manager:默認加載../conf下的所有配置文件,canal.instance.global.mode = manager,需要重寫CanalConfigClient類
3、遠程加載+spring:需要在數據庫配置,canal_instance_config表裏面canal.instance.global.mode = spring
4、遠程加載+manager:需要在數據庫配置,canal_instance_config表裏面canal.instance.global.mode = manager,需要重寫CanalConfigClient類
個人提醒:重寫CanalConfigClient類比較複雜,有寫的可以交流一下:QQ羣