Canalv1.1.4版本搭建HA集群
前提
Canal
上一個正式版是於2019-9-2
發布的v1.1.4
,筆者幾個月前把這個版本的Canal
推上了生產環境,部署了HA
集群。過程中雖然遇到不少的坑,但是在不出問題的前提下,Canal
的作用還是非常明顯的。上周的一次改造上線之後,去掉了原來對業務系統訂單數據通過RabbitMQ
實時推送的依賴,下游的統計服務完全通過上游業務主庫的binlog
事件進行聚合,從而實現了核心業務和實時統計兩個不同的模組解耦。
這篇文章簡單分析一下如何搭建生產環境下可靠的Canal
高可用集群。
Canal高可用集群架構
Canal
的HA
其實包含了服務端HA
和客戶端的HA
,兩者的實現原理差不多,都是通過Zookeeper
實例標識某個特定路徑下搶佔EPHEMERAL
(臨時)節點的方式進行控制,搶佔成功的一者會作為運行節點(狀態為running
),而搶佔失敗的一方會作為備用節點(狀態是standby
)。下文只分析服務端HA
集群搭建,因為一般情況下使用內建的數據管道例如Kafka
,基本屏蔽了客戶端的細節。假設客戶端使用了Kafka
,也就是Canal
從主庫同步到的binlog
事件最終會投放到Kafka
,那麼Canal
服務端HA
集群架構大致如下:
這是全局來看,一個運行的Canal
服務端,可以同時支援監聽多個上游資料庫的binlog
,某個主庫解析配置的抽象在Canal
中的術語叫做Instance
(實例):
定義多個Instance
的操作很簡單,主配置文件$CANAL_HOME/conf/canal.properties
中的canal.destinations
配置項通過英文逗號分隔多個標識如:
# canal.destinations=[Instance標識1,Instance標識2...,Instance標識n]
canal.destinations=customer-service,payment-service
然後在$CANAL_HOME/conf
目錄下添加customer-service
和payment-service
文件夾,把原來的$CANAL_HOME/conf/example
文件夾中的instance.properties
拷貝過去,按需修改裡面的配置即可:
$CANAL_HOME
- conf
- customer-service
- instance.properties # 這裡主要配置customer-service主庫的連接資訊、過濾規則和目標topic的配置等等
配置 【canal.mq.topic = customer-service】
- payment-service
- instance.properties # 這裡主要配置payment-service主庫的連接資訊和過濾規則和目標topic的配置等等
配置 【canal.mq.topic = payment-service】
而Canal
最終解析好的binlog
事件會分別以topic
為customer-service
或payment-service
發送到Kafka
集群中,這樣就能確保不同數據源解析出來的binlog
不會混亂。
Canal會實時監聽每個Instance的配置文件instance.properties的變動,一旦發現配置文件有屬性項變更,會進行一次熱載入,原則是變更Instance的配置文件是不用重啟Canal服務的。
搭建Canal高可用集群
為了簡單起見,Zookeeper和Kafka使用單節點作為示例,實際上生產環境中建議Zookeeper或Kafka都使用奇數個(>=3)節點的集群。
筆者本地一台CentOS7.x
的虛擬機192.168.56.200
上安裝了Zookeeper
和Kafka
,本地開發機192.168.56.1
是Windows10
作業系統。虛擬機安裝了一個MySQL8.x
的服務端(Canal
要求MySQL
服務開啟binlog
支援特性,並且要求binlog
類型為ROW
,這兩點MySQL8.x
是默認開啟的),現在詳細講解在這兩台機器上搭建一個Canal
服務端HA
集群。
生產上搭建Canal服務端HA集群的機器最好在同一個內網中,並且建議伺服器由Canal獨佔,不要部署其他中間件或者應用,機器的配置建議4核心8GB記憶體起步。
下載當前(2020-08-22
)最新版本的canal.deployer-1.1.4.tar.gz:
拷貝和解壓canal.deployer-1.1.4.tar.gz
到虛擬機的/data/canal
目錄下,同時解壓一份在本地開發機的磁碟中。演示直接使用example
標識的Instance
。修改虛擬機/data/canal/conf/example/instance.properties
:
注意這裡筆者把topic
設置為和資料庫的schema
一致。其他細節項就不再進行展開,有興趣可以看筆者之前寫過的一篇文章《基於Canal和Kafka實現MySQL的Binlog近實時同步》,裡面很詳細地介紹了怎麼部署一個可用的Canal
單機服務,包括了MySQL
、Zookeeper
和Kafka
的安裝和使用。
同理,在開發機中的對應的配置文件中添加一模一樣的配置項,但是canal.instance.mysql.slaveId
配置項需要每個實例唯一,並且不能和主庫的serverId
衝突,例如:
# 虛擬機中的配置
canal.instance.mysql.slaveId=654321
# 開發機中的配置
canal.instance.mysql.slaveId=654322
然後修改虛擬機/data/canal/conf/canal.properties
配置,修改項主要包括:
Key | Value |
---|---|
canal.zkServers |
填寫Zookeeper 集群的host:port ,這裡填寫192.168.56.200:2181 |
canal.serverMode |
kafka |
canal.instance.global.spring.xml |
classpath:spring/default-instance.xml (一定要修改為此配置,基於Zookeeper的集群管理依賴於此配置) |
canal.mq.servers |
填寫Kafka 集群的host:port ,這裡填寫192.168.56.200:9092 |
其他配置項可以按需修改。對於canal.properties
,Canal
多個集群節點可以完全一致,寫好一份然後拷貝使用即可。接著可以分別啟動兩個Canal
服務,一般來說,先啟動的節點會成為running
節點:
- 對於
Linux
系統,可以使用命令sh $CANAL_HOME/bin/startup.sh
啟動Canal
。 - 對於
Windows
系統,直接掛起命令介面執行$CANAL_HOME/bin/startup.bat
腳本即可。
Windows啟動如果控制台報錯ch.qos.logback.core.LogbackException: Unexpected filename extension of file…,其實是因為腳本中的logback配置文件路徑佔位符的變數沒有預先設置值,見下圖:
Linux
下的啟動日誌(example.log
):
Windows
下的啟動日誌(canal.log
):
測試Canal高可用集群
先啟動虛擬機中的Canal
服務,再啟動本地開發機中的Canal
服務:
可見當前的cluster
列表中包含了兩個host:port
,而running
節點中的資訊只包含虛擬機的host:port
,意味著當前運行節點時虛擬機中的Canal
服務,本地開發機中的Canal
服務作為備用節點。此時可以嘗試在虛擬機中執行sh stop.sh
關閉Canal
服務:
可見cluster
列表只剩下本地開發機中的Canal
服務的host:port
,而running
節點中的資訊也是指向此服務資訊。至此成功驗證了Canal
主備模式的切換。此時可以再驗證一下開發機中的example.log
:
說說Canal保存在Zookeeper中的數據節點
前文使用ZooInspector展示了Canal
保存在Zookeeper
中的節點資訊,這裡簡單分析一下。節點樹的結構如下:
節點路徑 | 描述 |
---|---|
/otter/canal |
根目錄 |
/otter/canal/cluster |
Canal 集群節點資訊 |
/otter/canal/destinations |
Canal 所有Instance 的資訊 |
/otter/canal/cluster
路徑的展開如下:
# 其實就是掛載了所有集群節點的host:port資訊
/otter/canal/cluster
- 192.168.56.1:11111
- 172.17.0.1:11111
/otter/canal/destinations
路徑會相對複雜,展開的資訊如下:
/otter/canal/destinations
- Instance標識
- running 記錄當前為此Instance提供服務狀態為running的Canal節點 [EPHEMERAL類型]
- cluster 記錄當前為此Instance提供服務的Canal集群節點列表
- Client序號標識
- running 客戶端當前正在讀取的running節點 [EPHEMERAL類型]
- cluster 記錄當前讀取此Instance的客戶端節點列表
- cursor 記錄客戶端讀取的position資訊
# 例如
/otter/canal/destinations
- example
- running -> {"active":true,"address":"192.168.56.1:11111"}
- cluster
- 192.168.56.1:11111
- 172.17.0.1:11111
- 1001
- running
- cluster
- cursor
理解各個路徑存放的資訊,有利於在Canal
集群出現故障的時候結合日誌進行故障排查。
小結
Canal
集群已經在生產跑了一段時間,大部分的問題和坑都已經遇到過,有些問題通過了屏蔽某些開關解決,一些遺留無法解決的問題也想辦法通過預警手段人工介入處理。Canal
的HA
其實是比較典型的主備模式,也就是同一個時刻,只有單個Canal
服務對單個Instance
(Destination
)進行處理,想了下確實好像這樣才能確保主備中繼日誌同步的基本有序,備用節點其實是完全划水不工作的(除了監聽Zookeeper
中的路徑變更),一旦running
節點出現故障或者宕機,備用節點就會提升為running
節點,確保集群的可用性。
(本文完 c-3-d e-a-20200822)