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

猜你喜欢

转载自blog.csdn.net/u013200380/article/details/81082899