canal-1

启动入口CanalLauncher,假定intance为newAssert

CanalController

初始化

1.初始化instance config
2.new出embededCanalServer和canalServerWithNetty
3.初始化zkclientx
4.初始化ServerRunningMonitors,为每一个instance创建一个serverRunningMonitor,serverRunningMonitor里面的核心组件是serverRunningListener,这个listener封装了embededCanalServer的相关具体操作
5.如果是自动扫描,初始化instanceAction和instanceConfigMonitors

start

embededCanalServer.start();
这个不是真正的启动,只是生成了两个canalInstance
我们从上篇整体架构中已经知道,生成canalInstance有两种方式,远程获取canal配置或者加载本地spring配置,默认使用的是本地spring配置。
生成instance的时候同时生成了它包含的组件
`
public interface CanalInstance extends CanalLifeCycle {

String getDestination();

CanalEventParser getEventParser();

CanalEventSink getEventSink();

CanalEventStore getEventStore();

CanalMetaManager getMetaManager();

CanalAlarmHandler getAlarmHandler();

/**
 * 客户端发生订阅/取消订阅行为
 */
boolean subscribeChange(ClientIdentity identity);

}
`

真正的启动在serverRunningMonitor

public void start() {
        super.start();
        processStart();
        if (zkClient != null) {
            // 如果需要尽可能释放instance资源,不需要监听running节点,不然即使stop了这台机器,另一台机器立马会start
            String path = ZookeeperPathUtils.getDestinationServerRunning(destination);
            zkClient.subscribeDataChanges(path, dataListener);

            initRunning();
        } else {
            processActiveEnter();// 没有zk,直接启动
        }
    }

如上图,

前置逻辑--processStart
public void processStart() {
        if (zkclientx != null) {
            final String path = ZookeeperPathUtils.getDestinationClusterNode(destination, ip + ":"
                    + port);
            initCid(path);
            zkclientx.subscribeStateChanges(new IZkStateListener() {

                public void handleStateChanged(KeeperState state) throws Exception {

                }

                public void handleNewSession() throws Exception {
                    initCid(path);
                }
            });
        }

先initCid,即初始化了如下zk节点
/otter/canal/destinations/newAsset/cluster/10.254.124.165:11111
并订阅该节点的状态变化


canal-1_第1张图片
image.png
监听running节点

我们先看下running节点的内容


canal-1_第2张图片
image.png

监听指定instance的running节点
/otter/canal/destinations/newAsset/running
zkClient.subscribeDataChanges(path, dataListener)
我们看下这个

dataListenerdataListener = 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
                    release = true;
                    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);
                }
            }

        };
initRunning
 private void initRunning() {
        if (!isStart()) {
            return;
        }

        String path = ZookeeperPathUtils.getDestinationServerRunning(destination);
        // 序列化
        byte[] bytes = JsonUtils.marshalToByte(serverData);
        try {
            mutex.set(false);
            //创建zk的runinning节点,写入serverData
            zkClient.create(path, bytes, CreateMode.EPHEMERAL);
            activeData = serverData;
            //轮到自己作为activie,需要载入上一个active的上下文数据
            processActiveEnter();
            mutex.set(true);
        } catch (ZkNodeExistsException e) {
       } 
    }

很显然,对于newAsset的running节点的订阅和监控,可以使得newAsset在多个节点漂移
我们看下这个processActiveEnter,这个是ServerRunningListener的方法

   public void processActiveEnter() {
        try {
            MDC.put(CanalConstants.MDC_DESTINATION, String.valueOf(destination));
            embededCanalServer.start(destination);
        } finally {
            MDC.remove(CanalConstants.MDC_DESTINATION);
        }
    }

终于开始启动实例了。。。。
我们看看canalInstance有哪些组件

public interface CanalInstance extends CanalLifeCycle {

    String getDestination();

    CanalEventParser getEventParser();

    CanalEventSink getEventSink();

    CanalEventStore getEventStore();

    CanalMetaManager getMetaManager();

    CanalAlarmHandler getAlarmHandler();

    /**
     * 客户端发生订阅/取消订阅行为
     */
    boolean subscribeChange(ClientIdentity identity);
}

总结

canalLauncher->serverRunningMonitor->serverRunningListener->embededServer->canalInstance

你可能感兴趣的:(canal-1)