使用zookeeper解决程序在不同集群之间运行的高可用

package enn.cn.util;
/**
 * Created by Administrator on 2017/9/18.
 */

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class DistributedLock implements Watcher {
    private static int threadId;
    private static ZooKeeper zk = null;
    private static String selfPath;
    private static String waitPath;
    private static String LOG_PREFIX_OF_THREAD;
    private static final int SESSION_TIMEOUT = 10000;
    private static  String GROUP_PATH;
    private static  String SUB_PATH;
    private static final String CONNECTION_STRING = "host16:2181";
    private static Object object;
    private static String methodName;
    private static final int THREAD_NUM = 1;
    //确保连接zk成功;
    private CountDownLatch connectedSemaphore = new CountDownLatch(1);
    //确保所有线程运行结束;
    private static  CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
    private static  Logger log = LoggerFactory.getLogger(DistributedLock.class);

    public DistributedLock(int id, String group_path, String sub_path) {
        this.threadId = id;
        this.GROUP_PATH = group_path;
        this.SUB_PATH = sub_path;
        LOG_PREFIX_OF_THREAD = "【第" + threadId + "个线程】";
    }


    /*
    *  根据某个对象的名称和方法去执行该方法
    *
    */
    public static void execute() {
        Class clazz = object.getClass();
        Method m1;
        try {
            m1 = clazz.getDeclaredMethod(methodName);
            m1.invoke(object);
        } catch (NoSuchMethodException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * 获取锁
     *
     * @return
     */
    public  void getLock() throws KeeperException, InterruptedException {
        //EPHEMERAL_SEQUENTIAL临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名
        selfPath = zk.create(SUB_PATH, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        log.info(LOG_PREFIX_OF_THREAD + "创建锁路径:" + selfPath);
        if (checkMinPath()) {
            getLockSuccess();
        }
    }

    /**
     * 创建节点
     *
     * @param path 节点path
     * @param data 初始数据内容
     * @return
     */
    public boolean createPath(String path, String data, boolean needWatch) throws KeeperException, InterruptedException {
        if (zk.exists(path, needWatch) == null) {
            log.info(LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "
                    + this.zk.create(path,
                    data.getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT)
                    + ", content: " + data);
        }
        return true;
    }

    /**
     * 创建ZK连接
     *
     * @param connectString  ZK服务器地址列表
     * @param sessionTimeout Session超时时间
     */
    public void createConnection(String connectString, int sessionTimeout) throws IOException, InterruptedException {
        zk = new ZooKeeper(connectString, sessionTimeout, this);
        connectedSemaphore.await();
    }

    /**
     * 获取锁成功
     */
    public void getLockSuccess() throws KeeperException, InterruptedException {
        if (zk.exists(this.selfPath, false) == null) {
            log.error(LOG_PREFIX_OF_THREAD + "本节点已不在...");
            return;
        }
        log.info(LOG_PREFIX_OF_THREAD + "获取锁成功!");
        execute();
        log.info(LOG_PREFIX_OF_THREAD + "删除本节点:" + selfPath);
        zk.delete(this.selfPath, -1);
        releaseConnection();
        threadSemaphore.countDown();
    }


    /**
     * 关闭ZK连接
     */
    public void releaseConnection() {
        if (this.zk != null) {
            try {
                this.zk.close();
            } catch (InterruptedException e) {
            }
        }
        log.info(LOG_PREFIX_OF_THREAD + "释放连接");
    }

    /**
     * 检查自己是不是最小的节点
     *
     * @return
     */
    public boolean checkMinPath() throws KeeperException, InterruptedException {
        List<String> subNodes = zk.getChildren(GROUP_PATH, false);
        Collections.sort(subNodes);
        int index = subNodes.indexOf(selfPath.substring(GROUP_PATH.length() + 1));
        switch (index) {
            case -1: {
                log.error(LOG_PREFIX_OF_THREAD + "本节点已不在" + selfPath);
                return false;
            }
            case 0: {
                log.info(LOG_PREFIX_OF_THREAD + "子节点中,我在" + selfPath);
                return true;
            }
            default: {
                this.waitPath = GROUP_PATH + "/" + subNodes.get(index - 1);
                log.info(LOG_PREFIX_OF_THREAD + "获取子节点中,排在我前面的" + waitPath);
                try {
                    zk.getData(waitPath, true, new Stat());
                    return false;
                } catch (KeeperException e) {
                    if (zk.exists(waitPath, false) == null) {
                        log.info(LOG_PREFIX_OF_THREAD + "子节点中,排在我前面的" + waitPath + "已不在");
                        return checkMinPath();
                    } else {
                        throw e;
                    }
                }
            }
        }
    }

    @Override
    public void process(WatchedEvent event) {
        if (event == null) {
            return;
        }
        Event.KeeperState keeperState = event.getState();
        Event.EventType eventType = event.getType();
        if (Event.KeeperState.SyncConnected == keeperState) {
            if (Event.EventType.None == eventType) {
                log.info(LOG_PREFIX_OF_THREAD + "成功连接上ZK服务器");
                connectedSemaphore.countDown();
            } else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {
                log.info(LOG_PREFIX_OF_THREAD + "收排我前面节点已被删除");
                try {
                    if (checkMinPath()) {
                        getLockSuccess();
                    }
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } else if (Event.KeeperState.Disconnected == keeperState) {
            log.info(LOG_PREFIX_OF_THREAD + "与ZK服务器断开连接");
        } else if (Event.KeeperState.AuthFailed == keeperState) {
            log.info(LOG_PREFIX_OF_THREAD + "权限检查失败");
        } else if (Event.KeeperState.Expired == keeperState) {
            log.info(LOG_PREFIX_OF_THREAD + "会话失效");
        }
    }

    public static int getThreadId() {
        return threadId;
    }

    public static ZooKeeper getZk() {
        return zk;
    }

    public static String getSelfPath() {
        return selfPath;
    }

    public static String getWaitPath() {
        return waitPath;
    }

    public static String getLogPrefixOfThread() {
        return LOG_PREFIX_OF_THREAD;
    }

    public static int getSessionTimeout() {
        return SESSION_TIMEOUT;
    }

    public static String getGroupPath() {
        return GROUP_PATH;
    }

    public static String getSubPath() {
        return SUB_PATH;
    }

    public static String getConnectionString() {
        return CONNECTION_STRING;
    }

    public static Object getObject() {
        return object;
    }

    public static String getMethodName() {
        return methodName;
    }

    public static int getThreadNum() {
        return THREAD_NUM;
    }

    public CountDownLatch getConnectedSemaphore() {
        return connectedSemaphore;
    }

    public static CountDownLatch getThreadSemaphore() {
        return threadSemaphore;
    }

    public static Logger getLog() {
        return log;
    }

    public static void setThreadId(int threadId) {
        DistributedLock.threadId = threadId;
    }

    public static void setZk(ZooKeeper zk) {
        DistributedLock.zk = zk;
    }

    public static void setSelfPath(String selfPath) {
        DistributedLock.selfPath = selfPath;
    }

    public static void setWaitPath(String waitPath) {
        DistributedLock.waitPath = waitPath;
    }

    public static void setLogPrefixOfThread(String logPrefixOfThread) {
        LOG_PREFIX_OF_THREAD = logPrefixOfThread;
    }

    public static void setGroupPath(String groupPath) {
        GROUP_PATH = groupPath;
    }

    public static void setSubPath(String subPath) {
        SUB_PATH = subPath;
    }

    public static void setObject(Object object) {
        DistributedLock.object = object;
    }

    public static void setMethodName(String methodName) {
        DistributedLock.methodName = methodName;
    }

    public void setConnectedSemaphore(CountDownLatch connectedSemaphore) {
        this.connectedSemaphore = connectedSemaphore;
    }

    public static void setThreadSemaphore(CountDownLatch threadSemaphore) {
        DistributedLock.threadSemaphore = threadSemaphore;
    }
}
 
 
package enn.cn.singlepoint;

import enn.cn.util.CommonContent;
import enn.cn.util.DistributedLock;
import org.apache.log4j.Logger;

/**
 * Created by Administrator on 2017/9/20.
 */
public class SingleSupplyOneMain {
    private static Logger log = Logger.getLogger(SingleSupplyOneMain.class);
    static DistributedLock dc;
    public static void main(String[] args) {
        new Thread() {
            @Override
            public void run() {
                try {
                    dc = new DistributedLock(1,"/singleLocks","/singleLocks/sub");
                    dc.createConnection(CommonContent.ZOOKEEPER_HOST, dc.getSessionTimeout());
                    //GROUP_PATH不存在的话,由一个线程创建
                    //注:如果一个jar包中有多个main方法要调用同一个zookeeper工具类,那么GROUP_PATH路径要不一样,以为一个main方法会创建一个分组
                    synchronized (dc.getConnectedSemaphore()) {
                        dc.createPath(dc.getGroupPath(), "该节点由线程" + 1 + "创建", true);
                    }
                    dc.setObject(new TimerManagerTask());
                    dc.setMethodName("execTask");
                    dc.getLock();
                } catch (Exception e) {
                    log.error("发布时出现异常:{}", e);
                    e.printStackTrace();
                }
            }
        }.start();
        try {
            dc.getThreadSemaphore().await();
            log.info("所有线程运行结束!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值