package com.baidu.disconf.core.common.zookeeper.inner; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.KeeperState; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.ZooKeeper.States; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 连接管理 * * @author liaoqiqi */ public class ConnectionWatcher implements Watcher { protected static final Logger LOGGER = LoggerFactory.getLogger(ConnectionWatcher.class); // 10 秒会话时间 ,避免频繁的session expired private static final int SESSION_TIMEOUT = 10000; // 3秒 private static final int CONNECT_TIMEOUT = 3000; protected ZooKeeper zk; private CountDownLatch connectedSignal = new CountDownLatch(1); private static String internalHost = ""; // 是否调试状态 private boolean debug = false; /** * @param debug */ public ConnectionWatcher(boolean debug) { this.debug = debug; } /** * @param hosts * * @return void * * @throws IOException * @throws InterruptedException * @Description: 连接ZK * @author liaoqiqi * @date 2013-6-14 */ public void connect(String hosts) throws IOException, InterruptedException { internalHost = hosts; zk = new ZooKeeper(internalHost, SESSION_TIMEOUT, this); // 连接有超时哦 connectedSignal.await(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS); LOGGER.info("zookeeper: " + hosts + " , connected."); } /** * 当连接成功时调用的 */ @Override public void process(WatchedEvent event) { if (event.getState() == KeeperState.SyncConnected) { LOGGER.info("zk SyncConnected"); connectedSignal.countDown(); } else if (event.getState().equals(KeeperState.Disconnected)) { // 这时收到断开连接的消息,这里其实无能为力,因为这时已经和ZK断开连接了,只能等ZK再次开启了 LOGGER.warn("zk Disconnected"); } else if (event.getState().equals(KeeperState.Expired)) { if (!debug) { // 这时收到这个信息,表示,ZK已经重新连接上了,但是会话丢失了,这时需要重新建立会话。 LOGGER.error("zk Expired"); // just reconnect forever reconnect(); } else { LOGGER.info("zk Expired"); } } else if (event.getState().equals(KeeperState.AuthFailed)) { LOGGER.error("zk AuthFailed"); } } /** * 含有重试机制的retry,加锁, 一直尝试连接,直至成功 */ public synchronized void reconnect() { LOGGER.info("start to reconnect...."); int retries = 0; while (true) { try { if (!zk.getState().equals(States.CLOSED)) { break; } LOGGER.warn("zookeeper lost connection, reconnect"); close(); connect(internalHost); } catch (Exception e) { LOGGER.error(retries + "\t" + e.toString()); // sleep then retry try { int sec = ResilientActiveKeyValueStore.RETRY_PERIOD_SECONDS; LOGGER.warn("sleep " + sec); TimeUnit.SECONDS.sleep(sec); } catch (InterruptedException e1) { } } } } /** * @return void * * @throws InterruptedException * @Description: 关闭 * @author liaoqiqi * @date 2013-6-14 */ public void close() throws InterruptedException { zk.close(); } public ZooKeeper getZk() { return zk; } public void setZk(ZooKeeper zk) { this.zk = zk; } }