Canalv1.1.4版本搭建HA叢集

throwable發表於2020-09-05

前提

Canal上一個正式版是於2019-9-2釋出的v1.1.4,筆者幾個月前把這個版本的Canal推上了生產環境,部署了HA叢集。過程中雖然遇到不少的坑,但是在不出問題的前提下,Canal的作用還是非常明顯的。上週的一次改造上線之後,去掉了原來對業務系統訂單資料通過RabbitMQ實時推送的依賴,下游的統計服務完全通過上游業務主庫的binlog事件進行聚合,從而實現了核心業務和實時統計兩個不同的模組解耦。

這篇文章簡單分析一下如何搭建生產環境下可靠的Canal高可用叢集。

Canal高可用叢集架構

CanalHA其實包含了服務端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-servicepayment-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事件會分別以topiccustomer-servicepayment-service傳送到Kafka叢集中,這樣就能確保不同資料來源解析出來的binlog不會混亂。

Canal會實時監聽每個Instance的配置檔案instance.properties的變動,一旦發現配置檔案有屬性項變更,會進行一次熱載入,原則是變更Instance的配置檔案是不用重啟Canal服務的。

搭建Canal高可用叢集

為了簡單起見,Zookeeper和Kafka使用單節點作為示例,實際上生產環境中建議Zookeeper或Kafka都使用奇數個(>=3)節點的叢集。

筆者本地一臺CentOS7.x的虛擬機器192.168.56.200上安裝了ZookeeperKafka,本地開發機192.168.56.1Windows10作業系統。虛擬機器安裝了一個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單機服務,包括了MySQLZookeeperKafka的安裝和使用。

同理,在開發機中的對應的配置檔案中新增一模一樣的配置項,但是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.propertiesCanal多個叢集節點可以完全一致,寫好一份然後拷貝使用即可。接著可以分別啟動兩個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叢集已經在生產跑了一段時間,大部分的問題和坑都已經遇到過,有些問題通過了遮蔽某些開關解決,一些遺留無法解決的問題也想辦法通過預警手段人工介入處理。CanalHA其實是比較典型的主備模式,也就是同一個時刻,只有單個Canal服務對單個InstanceDestination)進行處理,想了下確實好像這樣才能確保主備中繼日誌同步的基本有序,備用節點其實是完全划水不工作的(除了監聽Zookeeper中的路徑變更),一旦running節點出現故障或者當機,備用節點就會提升為running節點,確保叢集的可用性。

(本文完 c-3-d e-a-20200822)

相關文章