2、Canal-架构-Canal HA集群思考

集群目前可以分3类,高可用性集群(High Availability Cluster)HA、负载均衡集群(Load Balance Cluster)LB、高性能集群(High Performance Computing Cluster)HPC,这3类集群有什么区别呢?

集群类别:

一、高可用性集群HA

一个集群只有一台主机,其他的节点都是从机的模型,从机可能什么活都不干,只负担主机的后备,也可能做
一些任务型的工作,这部分工作不会关系数据的事务。 HA什么活都不干的集群:Canal,HA做部分活的集群:Kafka、ES主从模式集群等。HA重点侧重于高可用性,对数据一致性关注高。

二、负载均衡集群LB

集群的各个节点是平等的,通过路由算法共同负载整个整个业务。负载均衡集群更关注如何更大力度的使用整个集群的性能。对其数据的一致性的关注弱于HA架构。 LB集群是目前使用最多、架构最简单的集群方式,比如:dubbo、nginx等中间件使用负载均衡架构

三、高性能集群HPC

这种集群在科研行业用的比较多,也就是一个很大的任务,需要多台机器共同的算力才能完成。这类架构目前我们用的比较少,但是数据分析行业等这种架构用的比较多。这种架构是这3类架构中最复杂的架构,如何分解任务然后合并计算结果,如何分解任务对集群整个性能干扰最低,是非常难的解决方案。

Canal HA架构如何实现?

刚才啰嗦一堆架构类别还没有讲到今天的正题。但是我觉得这种概念的认知就像1+1=2,一切的东西都是建立在最简单的东西上面,下面讲讲Canal是如何实现的。Canal Ha启动过程是节点初始化,然后启动节点,然后节点读取 zk /otter/canal/destinations/tms_0/running节点是否有数据,如果没有数据说明集群不存在主节点,本节点就尝试成为主节点,如果有节点默认以从节点身份启动。其原理利用zk节点的事务特性、zk节点订阅特性。

// HA机制启动入口
ServerRunningMonitor runningMonitor = ServerRunningMonitors.getRunningMonitor(destination);

//启动方法
public synchronized void start() {
        super.start();
        try {
            processStart();
            if (zkClient != null) {
                // 如果需要尽可能释放instance资源,不需要监听running节点,不然即使stop了这台机器,另一台机器立马会start
                String path = ZookeeperPathUtils.getDestinationServerRunning(destination);
                //ps:此处利用zk节点变化订阅功能,这点区别于监听,监听只会执行一次。作者认为监听导致节点没有测地关闭另外一台会立刻启动。其实监听中可以有判断逻辑。
                zkClient.subscribeDataChanges(path, dataListener);
                
                //尝试成为集群主节点
                initRunning();
            } else {
                processActiveEnter();// 没有zk,直接启动
            }
        } catch (Exception e) {
            logger.error("start failed", e);
            // 没有正常启动,重置一下状态,避免干扰下一次start
            stop();
        }

}

//Canal zk监听事件实现利用zk的节点订阅功能
public ServerRunningMonitor(){
        // 创建父节点
        dataListener = new IZkDataListener() {

            public void handleDataChange(String dataPath, Object data) throws Exception {
                MDC.put("destination", destination);
                ServerRunningData runningData = JsonUtils.unmarshalFromByte((byte[]) data, ServerRunningData.class);
                if (!isMine(runningData.getAddress())) {
                    mutex.set(false);
                }

                if (!runningData.isActive() && isMine(runningData.getAddress())) { // 说明出现了主动释放的操作,并且本机之前是active
                    releaseRunning();// 彻底释放mainstem
                }

                activeData = (ServerRunningData) runningData;
            }

            public void handleDataDeleted(String dataPath) throws Exception {
                MDC.put("destination", destination);
                mutex.set(false);
                if (!release && activeData != null && isMine(activeData.getAddress())) {
                    // 如果上一次active的状态就是本机,则即时触发一下active抢占
                    initRunning();
                } else {
                    // 否则就是等待delayTime,避免因网络瞬端或者zk异常,导致出现频繁的切换操作
                    delayExector.schedule(new Runnable() {

                        public void run() {
                            initRunning();
                        }
                    }, delayTime, TimeUnit.SECONDS);
                }
            }

        };

    }

 //尝试成为主节点
 private void initRunning() {
        if (!isStart()) {
            return;
        }

        String path = ZookeeperPathUtils.getDestinationServerRunning(destination);
        // 序列化
        byte[] bytes = JsonUtils.marshalToByte(serverData);
        try {
            //如果zk runing节点创建成功就该节点就成为集群主节点
            mutex.set(false);
            zkClient.create(path, bytes, CreateMode.EPHEMERAL);
            activeData = serverData;
            processActiveEnter();// 触发一下事件
            mutex.set(true);
            release = false;
        } catch (ZkNodeExistsException e) {
            //如果有主节点执行此处代码
            bytes = zkClient.readData(path, true);
            if (bytes == null) {// 如果不存在节点,立即尝试一次
                initRunning();
            } else {
                activeData = JsonUtils.unmarshalFromByte(bytes, ServerRunningData.class);
            }
        } catch (ZkNoNodeException e) {
            zkClient.createPersistent(ZookeeperPathUtils.getDestinationPath(destination), true); // 尝试创建父节点
            initRunning();
        }
    }

你可能感兴趣的:(#,Canal)