前提
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)