Canal高可用架構部署

zlt2000發表於2021-03-25

一、前言

canal 是阿里的一款開源專案,純 Java 開發。基於資料庫增量日誌解析,提供增量資料訂閱&消費,目前主要支援了 MySQL(也支援 mariaDB)。

  1. canal 模擬 mysql slave 的互動協議,偽裝自己為 mysql slave,向 mysql master傳送 dump 協議;
  2. mysql master 收到 dump 請求,開始推送binary log給 slave(也就是canal)
  3. canal 解析 binary log物件(原始為byte流)。

 

總體架構

 

二、部署準備

下載地址
https://github.com/alibaba/canal/releases

分別下載:canal.admin、canal.deployer、canal.adapter

PS:只有1.1.5以上版本才支援es7.x

 

其他依賴

  1. JDK1.8
  2. MySQL:用於canal-admin儲存配置和節點等相關資料
  3. Zookeeper

 

三、HA機制

整個 HA 機制的控制主要是依賴了zookeeper的兩個特性:watcher、EPHEMERAL節點。canal的 HA 機制實現分為兩部分,canal server 和 canal client分別有對應的實現。

canal server實現流程如下:

  1. canal server 要啟動某個 canal instance 時都先向 zookeeper 進行一次嘗試啟動判斷 (實現:建立 EPHEMERAL 節點,誰建立成功就允許誰啟動);
  2. 建立 zookeeper 節點成功後,對應的 canal server 就啟動對應的 canal instance,沒有建立成功的 canal instance 就會處於 standby 狀態;
  3. 一旦 zookeeper 發現 canal server A 建立的節點消失後,立即通知其他的 canal server 再次進行步驟1的操作,重新選出一個 canal server 啟動instance;
  4. canal client 每次進行connect時,會首先向 zookeeper 詢問當前是誰啟動了canal instance,然後和其建立連結,一旦連結不可用,會重新嘗試connect。

PS: 為了減少對mysql dump的請求,不同server上的instance要求同一時間只能有一個處於running,其他的處於standby狀態。

 

canal client實現流程

  1. canal client 的方式和 canal server 方式類似,也是利用 zookeeper 的搶佔EPHEMERAL 節點的方式進行控制
  2. 為了保證有序性,一份 instance 同一時間只能由一個 canal client 進行get/ack/rollback操作,否則客戶端接收無法保證有序。

 

四、叢集部署

4.1. MySQL準備

4.1.1. 開啟binlog

MySQL的 my.cnf 中配置如下

[mysqld]
log-bin=mysql-bin # 開啟 binlog
binlog-format=ROW # 選擇 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定義,不要和 canal 的 slaveId 重複

注意:如果訂閱的是mysql的從庫,需求增加配置讓從庫日誌也寫到binlog裡面

log_slave_updates=1

可以通過在 mysql 終端中執行以下命令判斷配置是否生效:

show variables like 'log_bin';
show variables like 'binlog_format';

 

4.1.2. 授權賬號許可權

授權 canal 連結 MySQL 賬號具有作為 MySQL slave 的許可權, 如果已有賬戶可直接 grant:

CREATE USER canal IDENTIFIED BY 'canal';  
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;

 

4.2. 部署canal-admin

4.2.1. 作用

  1. 通過圖形化介面管理配置引數。
  2. 動態啟停 ServerInstance
  3. 檢視日誌資訊

 

4.2.2. 執行資料庫指令碼

執行 conf 目錄下載的 canal_manager.sql 腳步,初始化所需的庫表。

初始化SQL指令碼里會預設建立canal_manager的資料庫,建議使用root等有超級許可權的賬號進行初始化

 

4.2.3. 配置修改

執行 vim conf/application.yml

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

spring.datasource:
  address: 127.0.0.1:3306
  database: canal_manager
  username: canal
  password: canal
  driver-class-name: com.mysql.jdbc.Driver
  url: jdbc:mysql://${spring.datasource.address}/${spring.datasource.database}?useUnicode=true&characterEncoding=UTF-8&useSSL=false
  hikari:
    maximum-pool-size: 30
    minimum-idle: 1

canal:
  adminUser: admin
  adminPasswd: admin

修改 addressdatabaseusernamepassword 四個引數

 

4.2.4. 啟停命令

啟動

sh bin/startup.sh

停止

sh bin/stop.sh

 

4.2.5. 使用

通過 http://127.0.0.1:8089/ 訪問,預設密碼:admin/123456

4.2.5.1. 建立叢集

配置 叢集名稱ZK地址

 

配置 主配置,該配置為叢集內的所有Server例項共享的

主要修改以下配置:

  • canal.zkServers 配置zookeeper叢集地址
  • canal.instance.global.spring.xml 改為classpath:spring/default-instance.xml

 

4.2.5.2. 建立Server

配置項:

  • 所屬叢集,可以選擇為單機 或者 叢集。一般單機Server的模式主要用於一次性的任務或者測試任務
  • Server名稱,唯一即可,方便自己記憶
  • Server Ip,機器ip
  • admin埠,canal 1.1.4版本新增的能力,會在canal-server上提供遠端管理操作,預設值11110
  • tcp埠,canal提供netty資料訂閱服務的埠
  • metric埠, promethues的exporter監控資料埠 (未來會對接監控)

多臺Server關聯同一個叢集即可形成主備HA架構

 

4.2.5.3. 建立Instance

每個 Instance 關聯一個同步的資料來源,如果有多個資料來源需要同步則需要建立多個 例項

  1. 先填寫例項名
  2. 選擇剛剛建立的叢集
  3. 載入模板配置

 

主要修改以下配置:

  • canal.instance.master.address 配置要同步的資料庫地址
  • canal.instance.dbUsername 資料庫使用者名稱(需同步許可權)
  • canal.instance.dbPassword 資料庫密碼
  • canal.instance.filter.regex mysql 資料解析關注的表,Perl正規表示式.多個正則之間以逗號(,)分隔,轉義符需要雙斜槓(\)

canal.instance.filter.regex常見例子:

  1. 所有表:.* or .\..
  2. canal schema下所有表: canal\..*
  3. canal下的以canal打頭的表:canal\.canal.*
  4. canal schema下的一張表:canal.test1
  5. 多個規則組合使用:canal\..*,mysql.test1,mysql.test2 (逗號分隔)
    注意:此過濾條件只針對row模式的資料有效(ps. mixed/statement因為不解析sql,所以無法準確提取tableName進行過濾)

 

4.3. 部署canal-deployer

4.3.1. 作用

  1. 偽裝成 MySQL 的從庫,同步主庫的binlog日誌。
  2. 解析並結構化 binary log 物件。

 

4.3.2. 修改配置

執行 vim conf/canal_local.properties 修改配置項 canal.admin.manager 為canal-admin的地址

 

4.3.3. 啟停命令

使用 local 配置啟動

bin/startup.sh local

停止

bin/stop.sh

 

4.4. 部署canal-adapter

4.4.1. 作用

  1. 對接上游訊息,包括kafka、rocketmq、canal-server
  2. 實現mysql資料的增量同步
  3. 實現mysql資料的全量同步
  4. 下游寫入支援mysql、es、hbase等

 

4.4.2. 修改配置

注意:目前 adapter 是支援動態配置的,也就是說修改配置檔案後無需重啟,任務會自動重新整理配置!

(1) 修改application.yml

執行 vim conf/application.yml 修改consumerProperties、srcDataSources、canalAdapters的配置

canal.conf:
  mode: tcp # kafka rocketMQ                # canal client的模式: tcp kafka rocketMQ
  flatMessage: true                         # 扁平message開關, 是否以json字串形式投遞資料, 僅在kafka/rocketMQ模式下有效
  syncBatchSize: 1000                       # 每次同步的批數量
  retries: 0                                # 重試次數, -1為無限重試
  timeout:                                  # 同步超時時間, 單位毫秒
  consumerProperties:
    canal.tcp.server.host:                  # 對應單機模式下的canal
    canal.tcp.zookeeper.hosts: 127.0.0.1:2181 # 對應叢集模式下的zk地址, 如果配置了canal.tcp.server.host, 則以canal.tcp.server.host為準
    canal.tcp.batch.size: 500               # tcp每次拉取訊息的數量
  srcDataSources:                           # 源資料庫
    defaultDS:                              # 自定義名稱
      url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true   # jdbc url 
      username: root                                            # jdbc 賬號
      password: 121212                                          # jdbc 密碼
  canalAdapters:                            # 介面卡列表
  - instance: example                       # canal 例項名或者 MQ topic 名
    groups:                                 # 分組列表
    - groupId: g1                           # 分組id, 如果是MQ模式將用到該值
      outerAdapters:                        # 分組內介面卡列表
      - name: es7                           # es7介面卡
        mode: rest                          # transport or rest
        hosts: 127.0.0.1:9200               # es地址
        security.auth: test:123456          # 訪問es的認證資訊,如沒有則不需要填
        cluster.name: my-es                 # 叢集名稱,transport模式必需配置
......           
  1. 一份資料可以被多個group同時消費, 多個group之間會是一個並行執行, 一個group內部是一個序列執行多個outerAdapters, 比如例子中logger和hbase
  2. 目前client adapter資料訂閱的方式支援兩種,直連canal server 或者 訂閱kafka/RocketMQ的訊息

 

(2) conf/es7目錄下新增對映配置檔案

adapter將會自動載入 conf/es7 下的所有 .yml 結尾的配置檔案

新增表對映的配置檔案,如 sys_user.yml 內容如下:

dataSourceKey: defaultDS
destination: example
groupId: g1
esMapping:
  _index: sys_user
  _id: id
  upsert: true
  sql: "select id, username, 
        , case when sex = 0 then '男' else '女' end sex
        , case when is_del = 0 then '否' else '是' end isdel
      from sys_user"
  etlCondition: "where update_time>={}"
  commitBatch: 3000
  • dataSourceKey 配置 application.ymlsrcDataSources 的值
  • destination 配置 canal.deployerInstance
  • groupId 配置 application.ymlcanalAdapters.groups 的值
  • _index 配置索引名
  • _id 配置主鍵對應的欄位
  • upsert 是否更新
  • sql 對映sql
  • etlCondition etl 的條件引數,全量同步時可以使用
  • commitBatch 提交批大小

sql對映支援多表關聯自由組合, 但是有一定的限制:

  1. 主表不能為子查詢語句
  2. 只能使用left outer join即最左表一定要是主表
  3. 關聯從表如果是子查詢不能有多張表
  4. 主sql中不能有where查詢條件(從表子查詢中可以有where條件但是不推薦, 可能會造成資料同步的不一致, 比如修改了where條件中的欄位內容)
  5. 關聯條件只允許主外來鍵的'='操作不能出現其他常量判斷比如: on a.role_id=b.id and b.statues=1
  6. 關聯條件必須要有一個欄位出現在主查詢語句中比如: on a.role_id=b.id 其中的 a.role_id 或者 b.id 必須出現在主select語句中

Elastic Search的mapping 屬性與sql的查詢值將一一對應(不支援 select *), 比如: select a.id as _id, a.name, a.email as _email from user, 其中name將對映到es mapping的name field, _email將 對映到mapping的_email field, 這裡以別名(如果有別名)作為最終的對映欄位. 這裡的_id可以填寫到配置檔案的 _id: _id對映

 

4.4.3. 啟停命令

啟動

bin/startup.sh

關閉

bin/stop.sh

 

4.5. 遺留問題

目前使用的 1.1.5-SNAPSHOT 版本由於還不是釋出版,發現 canal-adapter 的叢集部署有個bug,配置 zookeeper 地址後啟動會出現以下異常:

java.lang.LinkageError: loader constraint violation: when resolving method "com.alibaba.otter.canal.common.zookeeper.ZkClientx.create(Ljava/lang/String;Ljava/lang/Object;Lorg/apache/zookeeper/CreateMode;)Ljava/lang/String;" the class loader (instance of com/alibaba/otter/canal/connector/core/spi/URLClassExtensionLoader) of the current class, com/alibaba/otter/canal/client/impl/running/ClientRunningMonitor, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for the method's defining class, org/I0Itec/zkclient/ZkClient, have different Class objects for the type org/apache/zookeeper/CreateMode used in the signature
	at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor.initRunning(ClientRunningMonitor.java:122) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
	at com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor.start(ClientRunningMonitor.java:93) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
	at com.alibaba.otter.canal.client.impl.SimpleCanalConnector.connect(SimpleCanalConnector.java:108) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
	at com.alibaba.otter.canal.client.impl.ClusterCanalConnector.connect(ClusterCanalConnector.java:64) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]
	at com.alibaba.otter.canal.connector.tcp.consumer.CanalTCPConsumer.connect(CanalTCPConsumer.java:59) [connector.tcp-1.1.5-SNAPSHOT-jar-with-dependencies.jar:na]

 

有以下3個解決思路:

  1. adapter暫時使用單例項模式,等待官方解決問題。
  2. 自行修復bug
  3. 使用 MQ 模式(adapter則無需註冊到zookeeper了)

BUG 已修復:https://github.com/zlt2000/canal

 

五、監控

canal 預設已通過 11112 埠暴露同步相關的 metrics 資訊,只需通過整合 prometheusgrafana 即可實現實時監控同步情況,效果圖如下:

指標 簡述
Basic Canal instance 基本資訊。
Network bandwith 網路頻寬。包含inbound(canal server讀取binlog的網路頻寬)和outbound(canal server返回給canal client的網路頻寬)。
Delay Canal server與master延時;store 的put, get, ack操作對應的延時。
Blocking sink執行緒blocking佔比;dump執行緒blocking佔比(僅parallel mode)。
TPS(events) Canal instance消費所有binlog事件的TPS, 以MySQL binlog events為單位計算。
TPS(transaction) Canal instance 處理binlog的TPS,以MySQL transaction為單位計算。
TPS(tableRows) 分別對應store的put, get, ack操作針對資料表變更行的TPS。
Client requests Canal client請求server的請求數統計,結果按請求型別分類(比如get/ack/sub/rollback等)。
Client QPS client傳送請求的QPS,按GET與CLIENTACK分類統計。
Empty packets Canal client請求server返回空結果的統計。
Response time Canal client請求server的響應時間統計。
Store remain events Canal instance ringbuffer中堆積的events數量。
Store remain mem Canal instance ringbuffer中堆積的events記憶體使用量。

 

六、總結

  1. 準備MySQL
    • 開啟binlog(row模式)
    • 準備同步許可權的使用者
    • 建立canal-admin的庫表
  2. 準備zookeeper
  3. 部署canal-admin
    • 建立叢集
    • 建立server:關聯叢集
    • 建立Instance:關聯叢集,並配置源庫資訊
  4. 啟動canal-deployer
    • 關聯canal-admin
  5. 啟動canal-adapter
    • 關聯zookeeper
    • 配置源庫資訊
    • 關聯Instance
    • 配置目標庫資訊(es)
    • 新增對映配置檔案

 

掃碼關注有驚喜!

相關文章