搭建并运行基于HA模式的canal

阅读本文之前建议阅读这篇文章,canal单机模式:http://blog.csdn.net/hackerwin7/article/details/37923607


机器准备:

mysql:192.168.213.41:3306

canal server:192.168.213.42:11111 、192.168.213.43:11111

zookeeper:192.168.213.44:4180、192.168.213.45:4180、192.168.213.46:4180

安装与配置:

安装配置mysql-》运程登录这个节点

ssh [email protected]

可以apt-get  或者  源码安装都可以

配置my.cnf

[mysqld]  
log-bin=mysql-bin #添加这一行就ok  
binlog-format=ROW #选择row模式  
server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复  

新建canal用户,并赋予权限

CREATE USER canal IDENTIFIED BY 'canal';    
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';  
-- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;  
FLUSH PRIVILEGES; 

关于配置mysql用户密码问题:http://blog.csdn.net/hackerwin7/article/details/38040057


安装配置zookeeper-》下载zookeeper包  http://zookeeper.apache.org/releases.html#download

上传到远程节点

scp zookeeper.tar.gz [email protected]
scp zookeeper.tar.gz [email protected]
scp zookeeper.tar.gz [email protected]

登录远程节点(其他两个节点的擦作大同小异)

ssh [email protected]

解压包,配置,在cnof 目录新建zoo.cfg

tickTime=2000    
initLimit=5    
syncLimit=2    
dataDir=/home/canal/servers/zookeeper/data    
dataLogDir=/home/canal/servers/zookeeper/logs    
clientPort=4180
server.44=192.168.213.44:2888:3888  
server.45=192.168.213.45:2888:3888    
server.46=192.168.213.46:2888:3888

在目录上述dataDir的目录中创建myid, 将上述的三个数,server.X(我这里的X是44,45,46),中的X值写入myid文件,三台节点的myid这是不一样的哈。


安装canal-》 本机去下载canal的tar包 然后解压,地址:https://github.com/alibaba/canal/releases 。

本机分别上传包到两个远程节点

scp canal.tar.gz [email protected]:/home/canal/

scp canal.tar.gz [email protected]:~/
现在开始配置两个远程节点的canal

canal.properties:

# 用逗号隔开 且 不留空格
canal.zkServers=192.168.213.44:4180,192.168.213.45:4180,192.168.213.46:4180
canal.instance.global.spring.xml = classpath:spring/default-instance.xml
instance.properties:

canal.instance.mysql.slaveId = 1234 ##另外一台机器改成1235,保证slaveId不重复即可
canal.instance.master.address = 192.168.213.41:3306

启动运行:

1、mysql 启动与运行

/etc/init.d/mysqld restart #各版本mysql 启动命令不太相同
2、zookeeper 启动与运行

# 三个节点都要启动
zookeeper/bin/zkServer.sh start
然后在在三个节点中,随意取一个运行客户端

./zookeeper/bin/zkCli.sh -server 192.168.213.44:4180
3、canal 启动与运行

两个节点都启动canal

./canal/bin/startup.sh

状态检测:

进入任一个 zookeeper 节点,进入zookeeper客户端

./zookeeper/bin/zkCli.sh -server 192.168.213.44:4180

里面有get ls等命令来获取相应节点信息

# 获取正在运行的canal server
get /otter/canal/destinations/example/running
# 获取正在连接的canal client
get /otter/canal/destinations/example/1001/running
# 获取当前最后一次消费车成功的binlog
get /otter/canal/destinations/example/1001/cursor

现在我们来运行client 客户端 (见本文顶部的单机canal文章)

然后我们链接远程mysql,在mysql执行相关insert creat 等语句

然后观察client客户端的具体抓取信息。

HA模式切换:

现在我们来将通过zookeeper获取正在运行的canal server,然后我们将当前运行的canal server 正常关闭掉,我们可以通过zookeeper看到另一台canal server会成为正在运行的canal server,这就是HA模式的自动切换。这些都可以通过zookeeper查询到状态信息。



本系列下篇文章:canal HA 的异常切换与 client的数据抓取。

直接在这里附上执行了,注意循环try-catch的问题:

/**
 * Created by hp on 14-7-17.
 */
import java.net.InetSocketAddress;
import java.util.List;

import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.common.utils.AddressUtils;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.CanalEntry.Column;
import com.alibaba.otter.canal.protocol.CanalEntry.Entry;
import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;
import com.alibaba.otter.canal.protocol.CanalEntry.EventType;
import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;
import com.alibaba.otter.canal.protocol.CanalEntry.RowData;
import com.alibaba.otter.canal.protocol.exception.*;


import com.alibaba.otter.canal.client.*;
import com.alibaba.otter.canal.client.impl.running.ClientRunningMonitor;
import org.jetbrains.annotations.NotNull;

public class ClientSample {

    public static void main(String args[]) {
        // 创建链接
        CanalConnector connector = CanalConnectors.newClusterConnector("192.168.213.44:4180,192.168.213.45:4180,192.168.213.46:4180", "example", "", "");

        int batchSize = 1;
        int emptyCount = 0;
        while(true) {
            try {
                connector.connect();
                connector.subscribe(".*\\..*");
                while(true) {
                    Message messages = connector.getWithoutAck(1000);
                    long bachId = messages.getId();
                    int size = messages.getEntries().size();
                    if(bachId == -1 || size == 0) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("No DATA!!!!!!!!!!!!!!!!!!!!!!!!");
                    } else {
                        printEntry(messages.getEntries());
                    }
                }
            } catch (Exception e) {
                System.out.println("============================================================connect crash");
            } finally {
                connector.disconnect();
            }
        }
    }

    private static void printEntry(@NotNull List<Entry> entrys) {
        for (Entry entry : entrys) {
            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
                continue;
            }

            RowChange rowChage = null;
            try {
                rowChage = RowChange.parseFrom(entry.getStoreValue());
            } catch (Exception e) {
                throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),
                        e);
            }

            EventType eventType = rowChage.getEventType();
            System.out.println(String.format("================> binlog[%s:%s] , name[%s,%s] , eventType : %s",
                    entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
                    entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
                    eventType));

            for (RowData rowData : rowChage.getRowDatasList()) {
                if (eventType == EventType.DELETE) {
                    printColumn(rowData.getBeforeColumnsList());
                } else if (eventType == EventType.INSERT) {
                    printColumn(rowData.getAfterColumnsList());
                } else {
                    System.out.println("-------> before");
                    printColumn(rowData.getBeforeColumnsList());
                    System.out.println("-------> after");
                    printColumn(rowData.getAfterColumnsList());
                }
            }
        }
    }

    private static void printColumn(@NotNull List<Column> columns) {
        for (Column column : columns) {
            System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());
        }
    }
}







你可能感兴趣的:(HA,canal)