客户端是开发人员使用Zookeeper的主要的途径,以下内容将对Zookeeper的内部原理进行详细的学习和讲解。ZooKeeper的客户端主要有一下几个核心组件组成:
- Zookeeper:提供客户端访问ZooKeeper服务器的API.
- ClientWatchManager:负责管理客户端注册的Watcher.
- HostProvider:客户端地址列表管理器。
- ClientCnxn:客户端核心线程,其内部包含连个线程及SendThread和EvnentThread。SendThread是一个IO线程主要负责客户端和服务端之间的网络通信;后者是一个事件处理线程,主要负责对服务端时间进行处理。
客户端的整体架构如下:
实例
下面使用具体的实例结合源码来分析Zookeeper源码创建的过程:如下代码是一个单例的ZooKeeperSupport可以用来回去Zookeeper客户端对象:
1 public class ZookeeperSupport { 2 private static volatile ZooKeeper zooKeeper = null; // zookeeper连接,在初始化zk配置时设置 3 public static final Integer zooKeeperLock = new Integer(1); 4 public static boolean isUseZk = true; // 是否使用zk,默认使用,当zk连接发生异常时不再使用 5 public static final long ZK_CONNECT_TIMEOUT = 1L; //zk连接的超时时间设置,单位为秒 6 7 public static ZooKeeper getZooKeeper() { 8 // 如果zookeeper为null 或者连接不可用,则重新获取连接,一般情况下,不会触发 9 if (zooKeeper == null || !zooKeeper.getState().isAlive()) { 10 synchronized (zooKeeperLock) { 11 // 如果发现zk不再使用,则不再创建新的zk,直接返回 12 if (isUseZk) { 13 if (zooKeeper == null || !zooKeeper.getState().isAlive()) { 14 try { 15 zooKeeper = createNewZookeper(); 16 } catch (Exception e) { 17 Constant.log_cron.error("[initZkConfig] error happen where new zookeeper", e); 18 } 19 } 20 } 21 } 22 } 23 return zooKeeper; 24 } 25 26 public static void setZooKeeper(ZooKeeper zooKeeper) { 27 ZookeeperSupport.zooKeeper = zooKeeper; 28 } 29 30 /** 31 * zookeeper启动时,异步启动两个线程,所以new之后并不代表连接已经建立,此时如果调用zk的一些方法会抛ConnectionLoss的异常 32 * 为了避免这种情况,封装new方法,每次new的时候去等待连接已经建立才做后面的步骤 33 * 34 * @return 35 * @throws Exception 36 */ 37 public static ZooKeeper createNewZookeper() throws Exception { 38 CountDownLatch connectedLatch = new CountDownLatch(1); 39 ZooKeeper zooKeeper = new ZooKeeper(ZKConfig.getInstance().getConnectUrl(), ZKConfig.getInstance().getTimeout(), new DefaultWatcher(connectedLatch)); 40 if (States.CONNECTING == zooKeeper.getState()) { 41 boolean ret = connectedLatch.await(ZK_CONNECT_TIMEOUT, TimeUnit.SECONDS); 42 // 如果等待超时了,还没有收到连接成功的通知,则说明zk不可用,直接不用zk,并报警 43 if(!ret){ 44 isUseZk = false; 45 } 46 } 47 return zooKeeper; 48 } 49 }
为了使用Zookeeper服务,必需创建一个Zookeeper类的对象。在创建Zookeeper类的对象时客户端Session的建立是一个异步的过程,构造方法可能会在回话完成建立完成前立即返回,构造方法中的Watcher就是处理连接状态通知的接口。下面给出了DefaultWatcher实现:
1 public class DefaultWatcher implements Watcher { 2 private CountDownLatch connectedLatch; 3 public DefaultWatcher(CountDownLatch connectedLatch) { 4 this.connectedLatch = connectedLatch; 5 } 6 // 监控所有被触发的事件 7 @Override 8 public void process(WatchedEvent event) { 9 if (connectedLatch != null && event.getState() == KeeperState.SyncConnected) { 10 connectedLatch.countDown(); 11 } 12 } 13 }
源码分析
Zookeeper类一共有9个构造函数,具体源码如下:
参数名 |
说明 |
connectString |
Zookeeper服务器列表,格式host1:port1,host2:port2/Zookeeper-demo |
sessionTImeout |
回话超时时间,以毫秒为单位,在回话周期内客户端和服务器端通过心跳检测来维持回话的有效性,一旦在sessionTImeout周期内没有有效的心跳的检测,回话就会失效。 |
Watch |
事件处理器 |
canBeReadOnly |
表示是否支持只读模式。默认情况下,在ZK集群中,一个机器如果和集群中半数的的机器失去网络连接,那个这台机器将不再出来客户端请求(读/写)。但在某些情况下,当Zookeeper发生此类故障时允许Zookeeper服务器提供只读服务。 |
sessionID和sessionPasswd |
回话ID和回话秘钥,唯一确定一个回话。 |
时间: 2024-10-24 09:22:09