Package com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.monitor

Source Code of com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.monitor.StageMonitor

/*
* Copyright (C) 2010-2101 Alibaba Group Holding Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.monitor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkConnection;
import org.I0Itec.zkclient.exception.ZkException;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.apache.commons.lang.ClassUtils;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.KeeperException.NoNodeException;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import com.alibaba.otter.shared.arbitrate.impl.ArbitrateConstants;
import com.alibaba.otter.shared.arbitrate.impl.setl.ArbitrateLifeCycle;
import com.alibaba.otter.shared.arbitrate.impl.setl.helper.StageComparator;
import com.alibaba.otter.shared.arbitrate.impl.setl.helper.StagePathUtils;
import com.alibaba.otter.shared.arbitrate.impl.setl.monitor.Monitor;
import com.alibaba.otter.shared.arbitrate.impl.setl.monitor.MonitorScheduler;
import com.alibaba.otter.shared.arbitrate.impl.zookeeper.AsyncWatcher;
import com.alibaba.otter.shared.arbitrate.impl.zookeeper.ZooKeeperClient;
import com.alibaba.otter.shared.common.utils.zookeeper.ZkClientx;
import com.alibaba.otter.shared.common.utils.zookeeper.ZooKeeperx;

/**
* 所有process节点变化的监控
*
* <pre>
* 监控内容:
*  1. process列表的删除/新增
*  2. 每个process下的子节点(setl + end + error)节点的变化信息
* 数据获取:
*  1. 定义{@linkplain StageListener}
* 接口,并注册。即可监听监控内容的数据变化
*
* 注意点:
*  stageListener返回的processId为历史数据,可能出现以下情况:
*  1. 历史已就绪的process,因为系统的error错误或者人为的关闭同步队列,会导致当前的processId被删除
*  2. 此时该processId仍会被返回,需要在各个event中最后进行检查。判断Permit,是否出现error节点,process是否被删除等
*
* </pre>
*
* @author jianghang 2011-9-21 下午01:16:06
* @version 4.0.0
*/
public class StageMonitor extends ArbitrateLifeCycle implements Monitor {

    private static final Logger              logger            = LoggerFactory.getLogger(StageMonitor.class);

    private ExecutorService                  arbitrateExecutor;
    private ZkClientx                        zookeeper         = ZooKeeperClient.getInstance();
    private volatile List<Long>              currentProcessIds = new ArrayList<Long>();                                       // 当前的处于监控中的processId列表
    private volatile Map<Long, List<String>> currentStages     = new ConcurrentHashMap<Long, List<String>>();                 // 记录下stages信息

    private List<StageListener>              listeners         = Collections.synchronizedList(new ArrayList<StageListener>());

    private IZkChildListener                 processListener;

    public StageMonitor(Long pipelineId){
        super(pipelineId);

        processListener = new IZkChildListener() {

            public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
                if (currentChilds != null) {
                    initStage(currentChilds);
                }
            }
        };

        String path = StagePathUtils.getProcessRoot(getPipelineId());
        List<String> childs = zookeeper.subscribeChildChanges(path, processListener);
        initStage(childs);
        // syncStage();
        MonitorScheduler.register(this);
    }

    public void destory() {
        super.destory();
        if (logger.isDebugEnabled()) {
            logger.debug("## destory Stage pipeline[{}]", getPipelineId());
        }

        this.listeners.clear();
        String path = StagePathUtils.getProcessRoot(getPipelineId());
        zookeeper.unsubscribeChildChanges(path, processListener);
        MonitorScheduler.unRegister(this);
    }

    public void reload() {
        try {
            if (logger.isDebugEnabled()) {
                logger.debug("## reload Stage pipeline[{}]", getPipelineId());
            }

            initStage();
            for (Long processId : currentProcessIds) {
                reload(processId);
            }
        } catch (Exception cause) {
        }
    }

    /**
     * 只reload process这一级别的数据
     */
    public void reloadWithoutStage() {
        try {
            if (logger.isDebugEnabled()) {
                logger.debug("## reload Stage pipeline[{}]", getPipelineId());
            }

            initStage();
        } catch (Exception cause) {
        }
    }

    /**
     * 重新加载下processId信息
     */
    public void reload(Long processId) {
        try {
            if (logger.isDebugEnabled()) {
                logger.debug("## reload Stage pipeline[{}] process[{}]", getPipelineId(), processId);
            }

            initProcessStage(processId);
        } catch (Exception cause) {
        }
    }

    /**
     * 获取当前的process id列表
     */
    public List<Long> getCurrentProcessIds() {
        return getCurrentProcessIds(false);
    }

    /**
     * 获取当前的process id列表,指定是否强制刷新
     */
    public List<Long> getCurrentProcessIds(boolean reload) {
        if (reload) {
            reloadWithoutStage();
        }

        return currentProcessIds;
    }

    /**
     * 获取当前的process id对应的stage节点信息
     */
    public List<String> getCurrentStages(Long processId) {
        return getCurrentStages(processId, false);
    }

    /**
     * 获取当前的process id对应的stage节点信息,指定是否强制刷新
     */
    public List<String> getCurrentStages(Long processId, boolean reload) {
        if (reload) {
            reload(processId);
        }

        List<String> stages = currentStages.get(processId);
        if (stages == null) {
            stages = new ArrayList<String>();
        }
        return stages;
    }

    /**
     * 获取zk列表数据,无须同步处理
     */
    private void initStage() {
        // 1. 根据pipelineId构造对应的path
        String path = StagePathUtils.getProcessRoot(getPipelineId());
        // 2. 获取当前的所有process列表
        List<String> currentProcesses = zookeeper.getChildren(path);
        initStage(currentProcesses);
    }

    /**
     * 重新获取最新的process列表
     */
    private void initStage(List<String> currentProcesses) {
        // 3. 循环处理每个process
        List<Long> processIds = new ArrayList<Long>();
        for (String process : currentProcesses) {
            processIds.add(StagePathUtils.getProcessId(process));
        }
        Collections.sort(processIds); // 排序一下
        List<Long> needSyncProcessIds = new ArrayList<Long>();

        synchronized (currentProcessIds) { // 需要同步处理
            for (Long processId : processIds) {
                if (!currentProcessIds.contains(processId)) {
                    needSyncProcessIds.add(processId);
                }
            }

            for (Long currentProcessId : currentProcessIds) {
                if (!processIds.contains(currentProcessId)) {
                    currentStages.remove(currentProcessId);// 如果process已删除,删除本地的stage信息
                }
            }

            if (logger.isDebugEnabled()) {
                logger.debug("pipeline[{}] old processIds{},current processIds{}", new Object[] { getPipelineId(),
                        currentProcessIds, processIds });
            }

            currentProcessIds = processIds; // 切换引用,需设置为volatile保证线程安全&可见性
        }

        for (Long syncProcessId : needSyncProcessIds) {
            syncStage(syncProcessId);// 开始同步单个的process
            // boolean reply = initProcessStage(processId);// 通知下节点变化
            // if (!currentProcessIds.contains(processId) && reply == false) {
            // syncStage(processId);// 开始同步单个的process
            // } else {
            // // 如果上一次循环中已经添加了监控,则忽略掉本次处理, 避免重复监听
            // }
        }

        if (processIds.size() > 0) {// 尝试触发一下第一个process进行load
            initProcessStage(processIds.get(0));
        }
        processChanged(currentProcessIds);// 通知变化
    }

    private boolean initProcessStage(Long processId) {
        String path = null;
        try {
            // 1. 根据pipelineId+processId构造对应的path
            path = StagePathUtils.getProcess(getPipelineId(), processId);
            // 2. 获取当前的所有process列表
            List<String> currentStages = zookeeper.getChildren(path);
            return initProcessStage(processId, currentStages);
        } catch (ZkNoNodeException e) {
            // ignore,已经被termin处理
            return false;
        } catch (ZkException e) {
            return true;// 走到这一步代表已经出异常了,不需要监听
        }

    }

    /**
     * 处理指定的processId变化,返回结果true代表需要继续监听,false代表不需要监视
     */
    private boolean initProcessStage(Long processId, List<String> currentStages) {
        Collections.sort(currentStages, new StageComparator());
        if (logger.isDebugEnabled()) {
            logger.debug("pipeline[{}] processId[{}] with stage{}", new Object[] { getPipelineId(), processId,
                    currentStages });
        }

        this.currentStages.put(processId, currentStages);// 更新下stage数据
        stageChanged(processId, currentStages);// 通知stage变化
        // 2.1 判断是否存在了loaded节点,此节点为最后一个节点
        if (currentStages.contains(ArbitrateConstants.NODE_TRANSFORMED)) {
            return true;// 不需要监听了
        } else {
            return false;// 其他的状态需要监听
        }
    }

    // /**
    // * 监听process的新增/删除变化,触发process列表的更新
    // */
    // private void syncStage() {
    // // 1. 根据pipelineId构造对应的path
    // String path = null;
    // try {
    // path = StagePathUtils.getProcessRoot(getPipelineId());
    // // 2. 监听当前的process列表的变化
    // List<String> currentProcesses = zookeeper.getChildren(path, new AsyncWatcher() {
    //
    // public void asyncProcess(WatchedEvent event) {
    // MDC.put(ArbitrateConstants.splitPipelineLogFileKey, String.valueOf(getPipelineId()));
    // if (isStop()) {
    // return;
    // }
    //
    // // 出现session expired/connection losscase下,会触发所有的watcher响应,同时老的watcher会继续保留,所以会导致出现多次watcher响应
    // boolean dataChanged = event.getType() == EventType.NodeDataChanged
    // || event.getType() == EventType.NodeDeleted
    // || event.getType() == EventType.NodeCreated
    // || event.getType() == EventType.NodeChildrenChanged;
    // if (dataChanged) {
    // syncStage(); // 继续监听
    // // initStage(); // 重新更新
    // }
    // }
    // });
    //
    // // 3. 循环处理每个process
    // List<Long> processIds = new ArrayList<Long>();
    // for (String process : currentProcesses) {
    // processIds.add(StagePathUtils.getProcessId(process));
    // }
    //
    // Collections.sort(processIds); // 排序一下
    // // 判断一下当前processIds和当前内存中的记录是否有差异,如果有差异立马触发一下
    // if (!currentProcessIds.equals(processIds)) {
    // initStage(); // 立马触发一下
    // }
    // } catch (KeeperException e) {
    // syncStage(); // 继续监听
    // } catch (InterruptedException e) {
    // // ignore
    // }
    // }

    /**
     * 监听指定的processId节点的变化
     */
    private void syncStage(final Long processId) {
        // 1. 根据pipelineId + processId构造对应的path
        String path = null;
        try {
            path = StagePathUtils.getProcess(getPipelineId(), processId);
            // 2. 监听当前的process列表的变化
            IZkConnection connection = zookeeper.getConnection();
            // zkclient包装的是一个持久化的zk,分布式lock只需要一次性的watcher,需要调用原始的zk链接进行操作
            ZooKeeper orginZk = ((ZooKeeperx) connection).getZookeeper();
            List<String> currentStages = orginZk.getChildren(path, new AsyncWatcher() {

                public void asyncProcess(WatchedEvent event) {
                    MDC.put(ArbitrateConstants.splitPipelineLogFileKey, String.valueOf(getPipelineId()));
                    if (isStop()) {
                        return;
                    }

                    if (event.getType() == EventType.NodeDeleted) {
                        processTermined(processId); // 触发下节点删除
                        return;
                    }

                    // 出现session expired/connection losscase下,会触发所有的watcher响应,同时老的watcher会继续保留,所以会导致出现多次watcher响应
                    boolean dataChanged = event.getType() == EventType.NodeDataChanged
                                          || event.getType() == EventType.NodeDeleted
                                          || event.getType() == EventType.NodeCreated
                                          || event.getType() == EventType.NodeChildrenChanged;
                    if (dataChanged) {
                        // boolean reply = initStage(processId);
                        // if (reply == false) {// 出现过load后就不需要再监听变化,剩下的就是节点的删除操作
                        syncStage(processId);
                        // }
                    }
                }
            });

            Collections.sort(currentStages, new StageComparator());
            List<String> lastStages = this.currentStages.get(processId);
            if (lastStages == null || !lastStages.equals(currentStages)) {
                initProcessStage(processId); // 存在差异,立马触发一下
            }

        } catch (NoNodeException e) {
            processTermined(processId); // 触发下节点删除
        } catch (KeeperException e) {
            syncStage(processId);
        } catch (InterruptedException e) {
            // ignore
        }
    }

    // ======================== listener处理 ======================

    public void addListener(StageListener listener) {
        if (logger.isDebugEnabled()) {
            logger.debug("## pipeline[{}] add listener [{}]", getPipelineId(),
                         ClassUtils.getShortClassName(listener.getClass()));
        }

        this.listeners.add(listener);
    }

    public void removeListener(StageListener listener) {
        if (logger.isDebugEnabled()) {
            logger.debug("## pipeline[{}] remove listener [{}]", getPipelineId(),
                         ClassUtils.getShortClassName(listener.getClass()));
        }

        this.listeners.remove(listener);
    }

    private void processChanged(final List<Long> processIds) {
        for (final StageListener listener : listeners) {
            // 异步处理
            arbitrateExecutor.submit(new Runnable() {

                public void run() {
                    MDC.put(ArbitrateConstants.splitPipelineLogFileKey, String.valueOf(getPipelineId()));
                    listener.processChanged(processIds);
                }
            });
        }
    }

    private void stageChanged(final Long processId, final List<String> stages) {
        for (final StageListener listener : listeners) {
            // 异步处理
            arbitrateExecutor.submit(new Runnable() {

                public void run() {
                    MDC.put(ArbitrateConstants.splitPipelineLogFileKey, String.valueOf(getPipelineId()));
                    listener.stageChannged(processId, stages);
                }
            });
        }
    }

    private void processTermined(final Long processId) {
        for (final StageListener listener : listeners) {
            // 异步处理
            arbitrateExecutor.submit(new Runnable() {

                public void run() {
                    MDC.put(ArbitrateConstants.splitPipelineLogFileKey, String.valueOf(getPipelineId()));
                    listener.processTermined(processId);
                }
            });
        }
    }

    // ========== setter =========
    public void setArbitrateExecutor(ExecutorService arbitrateExecutor) {
        this.arbitrateExecutor = arbitrateExecutor;
    }

}
TOP

Related Classes of com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.monitor.StageMonitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.