canal原理的一些學習-2(HA 模式搭建)

簡介

  本篇主要介紹canal的HA集羣的搭建過程,以及結合自身使用過程的一些經歷介紹一些注意事項。

1. 集羣的搭建

這裏寫圖片描述
  HA集羣主要使用zookeeper來作爲一些metadata的存儲基地,以便於滿足集羣信息的共享。下面我們開始介紹集羣搭建的步驟。

1.1 機器準備

mysql: 10.29.15.227:3316 用戶:user_canal 密碼:pass_canal 
canal:  10.29.26.172 10.29.18.29
zookeeper: 10.29.17.46:2181,10.29.18.29:2181,10.29.26.172:2181

1.2 在兩臺canal機器上完成以下配置

1.2.1 修改canal.properties

canal.zkServers=10.20.144.51:2181
canal.instance.global.spring.xml = classpath:spring/default-instance.xml

1.2.2 新建對應的destionation

注意每個destionation 對應的是一個mysql實例

mkdir test_canal_db

修改對應的instance.properties文件(該文件從example/instance.properties拷貝而來)

canal.instance.mysql.slaveId = 1234 ##另外一臺機器改成1235,保證slaveId不重複即可
canal.instance.master.address = 10.29.61.119:3315

注意: 兩臺機器上的instance目錄的名字需要保證完全一致,HA模式是依賴於instance name進行管理,同時必須都選擇default-instance.xml配置

  這個時候去對應的日誌目錄下面 logs/test_canal_db/test_canal_db.log 只會看到一臺成功啓動的日誌。

然後這個時候可以去zookeeper中去看看對應存儲的一些元信息。

[zk: localhost:2181(CONNECTED) 6] get  /otter/canal/destinations/test_canal_db/running
{"active":true,"address":"10.29.18.29:11111","cid":1}

可以看到,這個時候對應的是有一個是master

2. 集羣原理的解釋

2.1 啓動的時候決定誰爲master

canal在啓動的時候會往zookeeper當中搶佔式的創建一個臨時節點 /otter/canal/destinations/{0}/running,搶佔成功的就是主節點,失敗的就是從節點。
這裏寫圖片描述

2.2 運行過程中的HA切換

  同時,canal server在啓動的時候會對這個節點進行監聽,一旦有變化,就會進行再次的搶佔。所以就通過這個實現了server端的HA。

2.3 客戶端的HA切換

  如果只有server端實現了切換肯定是不夠的,客戶端也需要仍然能夠連到正確的server上。所以客戶端也是使用了zookeeper來進行服務發現的。client也監聽了zk當中對應節點的信息變化。

3. 實際中運用的一些經驗總結

3.1 如何讓運行起來的canal(HA模式)恢復到初始狀態。

  在實際的應用中,有一次,dba因爲一些原因要對數據庫中的日誌進行重做,會停止我們canal連接的數據庫,導致我們的canal需要進行stop操作,同時,恢復後的binlog日誌也是新的格式。
這個時候的操作應該是:

停止canal的消費端—>
停止canal中的master—>
停止剛剛成爲master的另一臺機器—>
清除zookeeper中的信息(主要是client的信息,因爲這裏記錄了binlog的位置)。

這裏寫圖片描述
  在DBA將數據庫日誌重做以後,給出新的binlog信息,這個時候將binlog的信息配置到具體的 instance.properties當中

假如下面的DBA給出的binlog信息
canal.instance.master.journal.name=mysql-bin.000028
canal.instance.master.position=933520284

3.2 canal 連接的數據庫是slave,無法獲取到master的binlog的情況

這裏寫圖片描述
  在剛開始進行canal的上線配置的時候出現過一些問題。有一個問題的表現是,canal連接的庫是對應的server ip 是 10.29.211.78 ,但是mysql是一個集羣,我們連的是讀庫,寫庫在 10.29.211.43上面,出現的問題一直無法獲取到binlog,最開始懷疑是canal配置有問題,但是多個destionations ,其他的就正常,所以懷疑可能是數據庫配置的一些問題。後來懷疑可能是主從配置的一些問題。
在canal連的數據庫上執行

show variables like ‘log_%’


mysql>
mysql> show variables like 'log_%'\G
*************************** 1. row ***************************
...
*************************** 11. row ***************************
Variable_name: log_slave_updates
        Value: OFF
*************************** 26. row ***************************
Variable_name: log_warnings
        Value: 0
26 rows in set (0.08 sec)

mysql

  這裏可以看到對應的有一個參數叫 log_slave_updates 這個參數標識了從庫是否在同步完主庫的binlog信息後將該信息也寫入自己的binlog當中。
  默認情況下,slave庫在拿到master的binlog以後,會進行解析,將數據寫入當前的庫當中,但是對應的從master過來的binlog卻會被丟棄,所以,讀庫雖然有主庫master寫入的數據,卻不回有主庫對應的binlog,所以canal也就拿不到對應的binlog。

解決方案:
將mysql 從庫設置log_slave_updates=true

3.3 canal版本預警

這個坑踩的有點虧,當時canal已經到了v1.0.26,所以我們就選用了v1.0.25 ,結果過了幾個月後,這個版本被官方標識爲不建議生產使用,因爲它爆出了太多bug,所以權當預警吧。

4 對應的canal的配置

這裏將實際使用的配置貼出來,不一定是最好的,權作參考罷
vim canal.properties

canal.id= 1
canal.ip=
canal.port= 11111
canal.zkServers=10.29.17.46:2181,10.29.18.29:2181,10.29.26.172:2181
canal.zookeeper.flush.period = 1000
canal.file.flush.period = 1000
canal.instance.memory.buffer.size = 16384
canal.instance.memory.buffer.memunit = 1024
canal.instance.memory.batch.mode = MEMSIZE
canal.instance.detecting.enable = false
canal.instance.detecting.sql = select 1
canal.instance.detecting.interval.time = 3
canal.instance.detecting.retry.threshold = 3
canal.instance.detecting.heartbeatHaEnable = false
canal.instance.transaction.size =  1024
canal.instance.fallbackIntervalInSeconds = 60
canal.instance.network.receiveBufferSize = 16384
canal.instance.network.sendBufferSize = 16384
canal.instance.network.soTimeout = 30
canal.instance.filter.druid.ddl = true
canal.instance.filter.query.dcl = false
canal.instance.filter.query.dml = false
canal.instance.filter.query.ddl = false
canal.instance.filter.table.error = true
canal.instance.filter.rows = false
canal.instance.binlog.format = ROW,STATEMENT,MIXED
canal.instance.binlog.image = FULL,MINIMAL,NOBLOB
canal.instance.get.ddl.isolation = false
canal.destinations=searchapp,ll_social
canal.conf.dir = ../conf
canal.auto.scan = true
canal.auto.scan.interval = 5
canal.instance.global.mode = spring
canal.instance.global.lazy = false
canal.instance.global.spring.xml = classpath:spring/default-instance.xml

這裏只解釋一下HA模式的特別配置,canal.zkServers 和 canal.instance.global.spring.xml
配置了zookeeper相關的,在canal server啓動的時候會嘗試連接zookeeper,然後基於zookeeper中的數據來進行啓動。spring/default-instance.xml 則是對應的對metadata在zookeeper中的持久化的實現。

對應的數據庫的instance.properties配置

canal.instance.mysql.slaveId=2617201
canal.instance.master.address=10.29.15.227:3316
canal.instance.master.journal.name=
canal.instance.master.position=
canal.instance.master.timestamp=
canal.instance.tsdb.enable=false
canal.instance.dbUsername=canal_user
canal.instance.dbPassword=hF5mgndM
canal.instance.defaultDatabaseName=test
canal.instance.connectionCharset=UTF-8
canal.instance.filter.regex=ll_social\\.post,ll_social\\.group,ll_social\\.tag,ll_social\\.social_user,ll_social\\.post_group,ll_social\\.group_special_post,ll_social\\.comment,ll_social\\.v_post,ll_social\\.v_feed_hot,ll_social\\.post_fav_count,ll_social\\.post_reply_count,ll_social\\.user_group,ll_social\\.group_influence
canal.instance.filter.black.regex=

5.canal的HA客戶端使用

代碼示例如下



        String zookeeperHost = ConfigFace.getServerConfig().getString("zookeeper/host");
        CanalConnector connector = CanalConnectors.newClusterConnector(zookeeperHost,canalInstanceName, "", "");
        try {
            connector.connect();
            connector.subscribe("user_db.*");//Canal client端進行過濾
      //    connector.subscribe();//Canal Server端進行過濾
            while (true) {
                Message message = connector.getWithoutAck(1000); // 獲取指定數量的數據
                long batchId = message.getId();
                int size = message.getEntries().size();
                if (batchId == -1 || size == 0) {
                    Thread.sleep(1000);
                } else {
                    action(message.getEntries());//進行自己的業務處理
                }
                connector.ack(batchId); // 提交確認
                // connector.rollback(batchId); // 處理失敗, 回滾數據
            }
        } catch (Exception e) {
            connector.rollback();
            log.error("從canal 中獲取數據出錯!", e);
        } finally {
            connector.disconnect();
        }

可以看到HA的client也是通過zookeeper來獲取對應的server端的信息,並且會監聽zookeeper對應的節點信息,當running server 發生變化的時候會進行連接重建,所以可以實現HA。

參考:
http://blog.51cto.com/815632410/1420156

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章