一、 关于zookeeper_init函数的使用

问题描述:

开发人员在调用zookeeper_init函数时,若返回一个非空句柄zhandle_t  *zh,则认为初始化成功,这样可能会导致后续操作失败。

问题分析:

zhandle_t  *zookeeper_init(const char *host, watcher_fn fn, int recv_timeout,const   clientid_t *clientid, void *context, int flags) 函 数     返回一个zookeeper客户端与服务器通信的句柄,通常我们仅仅根据返回句柄情况来判断zookeeper 客户端与zookeeper服务器是否 建立连接。如果句柄为空则认为是失败,非空则成功。其实不然,zookeeper_init创建与ZooKeeper服务端通信的句柄以及对应于此句柄的会话,而会话的创建是一个异步的过程,仅当会话建立成功,zookeeper_init才返回一个可用句柄。

问题解决:

如何正确判断zookeepr_init初始化成功,可通过以下三种方式    
1、判断句柄的state是否为ZOO_CONNECTED_STATE状态,通过zoo_state(zh)判断状态值是否为ZOO_CONNECTED_STATE。

void ensureConnected()          
          {          
          pthread_mutex_lock(&lock);          
          while (zoo_state(zh)!=ZOO_CONNECTED_STATE)          
          {          
          pthread_cond_wait(&cond,&lock);          
          }          
          pthread_mutex_unlock(&lock);          
          }        

2、 在zookeeper_init中设置watcher,当zookeeper client与server会话建立后,触发watcher,当 watcher 的state = 3 (ZOO_CONNECTED_STATE), type = -1(ZOO_SESSION_EVENT)时,确认 会话成功建立,此时zookeeper client 初始化成功,可进行后续操作。    
3、业务上可以做保证,调用zookeeper_init返回句柄zh,通过该句柄尝试做zoo_exists()或zoo_get_data()等操作,根据操作结果来判断是否初始化成功。

二、 如何解决session失效问题

问题描述:

session失效,导致注册的watcher全部丢失。

问题分析:

如果zookeeper client与server在协商的超时时间内仍没有建立连接,当client与server再次建立连接时,由于session失效了,所有watcher已经被服务器端删除,从而导致所有的watcher需要重新注册。    
session 失效,zookeeper client与server重连后所有watcher都会收到两次触发,第一次 wathetr state = 1,type = -1(state = 1表示正在连接中,type = -1 表示session事件);第二次 watcher state = -112,type = -1(state = -112表示session失效)。

问题解决:

可以通过以下两种方法解决session失效问题    
1、获取触发session失效watcher后,业务重新注册所有的watcher。    
2、不能根本解决,但是可以减小session失效的概率。通过zookeeper client 与server设置更长的session超时时间。(参考下一问题)

三、 为什么zookeeper_init设置recv_timeout较长却没有效果

问题描述:

zookeeper_init设置recv_timeout 100000ms,但客户端与服务端断开连接30s就session失效了。

问题分析:

关于session超时时间的确定:zookeeper_init中设置的超时时间并非真正的session超时时间,session超时时间需要 server与client协商,业务通过zoo_recv_timeout(zhandle_t* zh)获取server与client协商后的超时时间。服务端: minSessionTimeout (默认值为:tickTime * 2) ,  maxSessionTimeout(默认值为:tickTime * 20), ticktime的默认值为2000ms。所以session范围为4s ~ 40s 。客户端:  sessionTimeout, 无默认值,创建实例时设置recv_timeout 值。经常会认为创建zookeeper客户端时设置了sessionTimeout为100s,而没有改变server端的配置,默认值是 不会生效的。 原因: 客户端的zookeeper实例在创建连接时,将sessionTimeout参数发送给了服务端,服务端会根据对应的  minSession/maxSession Timeout的设置,强制修改sessionTimeout参数,也就是修改为4s~40s 返回的参数。所以服务端不一定会以客户端的sessionTImeout做为session expire管理的时间。

问题解决:

增加zookeeper_init recv_timeout大小的同时,需要配置tickTime的值。    
tickTime设置是在 conf/zoo.cfg 文件中

# The number of milliseconds of each          
          ticktickTime=2000  (默认)          
          注: tickTime 心跳基本时间单位毫秒,ZK基本上所有的时间都是这个时间的整数倍。

import org.apache.zookeeper.*; 
     
    import java.io.IOException; 
    import java.util.concurrent.CountDownLatch; 
    import java.util.concurrent.ThreadLocalRandom; 
     
    public class ZKApplication implements Watcher { 
        private static final int SESSION_TIMEOUT = 3000; 
        private volatile static boolean shutdown; 
        private ZooKeeper zk; 
        private CountDownLatch connectedSignal = new CountDownLatch(1); 
     
        public void connect(String hosts) throws IOException, InterruptedException {
        try {
            System.out.println("Start to create the Zookeeper instance");
            zk = new ZooKeeper(hosts, SESSION_TIMEOUT, this);
            new Thread(new Runnable() {
                int count = 0;
                @Override
                public void run() {
                    while (count++ <= 1000) {
                        System.out.println(zk.getState());
                        try {

Thread.currentThread().sleep(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }

}).start();
        } catch(IOException e) {
            e.printStackTrace();
            throw e;
        }
       connectedSignal.await();

//Wait for the SyncConnected event occurs and process has been called, which will stop the waiting here.

}
        } 
     
        @Override 
        public void process(WatchedEvent event) { // Watcher interface 
            if (event.getState() == Event.KeeperState.SyncConnected) { 
                connectedSignal.countDown();  //connectedSignal.await() will no longer wait
            } 
        } 
     
        public void create(String groupName) throwsKeeperException, 
                InterruptedException { 
            String path = "/" + groupName; 
            String createdPath = zk.create(path, null/*data*/, ZooDefs.Ids.OPEN_ACL_UNSAFE, 
                    CreateMode.EPHEMERAL); //The znode will be deleted upon the session is closed. 
            System.out.println("Created " + createdPath); 
        } 
     
        public void close() throws InterruptedException { 
            zk.close(); 
        } 
     
        public static void main(String[] args) throws Exception { 
            final ZKApplication createGroup = new ZKApplication(); 
            String groupName = "zoo" + ThreadLocalRandom.current().nextInt(); 
            createGroup.connect(Host.HOST); 
            createGroup.create(groupName); 
            createGroup.close(); 
        } 
    }

上面的代码在Zookeeper没有启动的情况下,控制台输出1000次CONNECTING,也不退出,原因是已经发生了死锁问题。 引发死锁问题的是同步闭锁connectedSignal的使用,代码中的含义是客户端在connect方法中发起链接,然后connect一直等待直到 Watcher的process被回调将闭锁计数置零,通常这个没有问题,可是当Zookeeper压根没有启动的时候,这个代码会陷入死锁:

  1. 死锁发生在客户端阻塞等待于connectedSignal的await方法上,发生阻塞说明connectedSignal的计数没有置零,没有置零说明process没有调用,因为Zookeeper没有启动,所以说process没有被调用是合理的。代 码死锁于connectSignal的await方法上,那么意思是说,Zookeeper对象构造和会话建立过程应该是异步的,Zookeeper构造 方法返回后,另外一个会话创建线程会尝试建立会话,从代码的输出可以看出,会话状态一直是Connecting状态(试图创建会话,但尚未创建成功的状 态),Zookeeper的Javadoc清楚的说到Zookeeper实例和会话建立是异步的过程: Session establishment is asynchronous. This constructor will initiate connection to the server and return immediately - potentially (usually) before the session is fully established. The watcher argument specifies  the watcher that will be notified of any changes in state. This notification can come at any point before or after the constructor call has returned.
  2. 会 话建立的失败策略,比较直观的做法时当建立会话不成功时,第一时间通知客户,给客户以失败快速响应的机制。。。不过Zookeeper似乎采用另外一种策 略,连接不成功不告诉你,只有当调用Zookeeper的API时,才会真正的把连接未建立的异常抛给客户端,这么做的好处是在Zookeeper实例创 建但是由于连接不成功而处于Connecting状态时,如果在用户调用Zookeeper的API做具体的事情之前,Zookeeper恢复了,那么客 户端再调用Zookeeper的API进行操作时,跟Zookeeper一直处于健康的状态一样,这也体现了Zookeeper的高可用性。
  3. 会话的建立和会话的状态管理是在单独的线程中

了解了Zookeeper对象实例化和会话建立的异步性,一方面可以了解Zookeeper的设计策略,另一方面,也可以避免一些代码和同步策略导致的陷阱,比如代码中那样。

虽然代码中主线程已经阻塞于connect方法,可是当Zookeeper服务器启动后,Client会建立连接,然后回调Watcher的process方法,此时就会解锁,从这个角度上来说,这里的死锁应该不叫事,应该启动这个程序目的就是要有Zookeeper在运行才好,如果Zookeeper之后断了,connectionsignal这个闭锁已经不再起作用。

Zookeeper实例创建和会话建立的异步特性相关推荐

  1. ZooKeeper客户端源码(一)——向服务端建立连接+会话建立+心跳保持长连接

    首发CSDN:徐同学呀,原创不易,转载请注明源链接.我是徐同学,用心输出高质量文章,希望对你有所帮助. 一.从ZooKeeper实例初始化开始 ZooKeeper 提供了原生的客户端库,虽然不好用,但 ...

  2. zookeeper入门学习之java api会话建立《四》

    在上一篇zk中简单玩了下api的连接创建会话,也总是留下了很多坑,就是那些引申开来,搞不明白的问题.有时候想追究起来,问题总是那么无穷无尽,有时候问题比答案更有力度吧,到最后都是些哲学问题吗?存在的这 ...

  3. 《Abaqus GUI程序开发指南(Python语言)》——第一章 概述1.1 简单插件实例——创建带孔板有限元模型...

    本节书摘来自异步社区<Abaqus GUI程序开发指南(Python语言)>一书中的第1章,第1.1节,作者: 贾利勇 , 富琛阳子 , 贺高 , 周正光 更多章节内容可以访问云栖社区&q ...

  4. Veritas Flex 5150 实例管理-NetBackup实例创建

    创建应用程序实例概述 首先我们需要了解的是应用程序的实例包含如下信息: NetBackup主服务器 具有以下存储选项的NetBackup介质服务器.(媒体服务器重复数据删除池(MSDP).高级磁盘.C ...

  5. 5GC PDU Session Establishment PDU会话建立流程

    这里写目录标题 1.UE-AMF PDU Session Establishment Request 发起PDU会话建立请求 2.SMF Selection SMF的选择 3.AMF-SMF SmCo ...

  6. CloudStack初级部署与实例创建

    1 CloudStack 1.1 查看并修改虚拟机网络 打开虚拟机VMware Workstation,选择菜单栏"编辑"->虚拟网络编辑器,查看VMnet8的子网地址. 每 ...

  7. PDU会话建立流程(8)-SM Policy Association的建立

    相关文章会在公众号同步更新.公众号:5G通信大家学 持续更新的相关5G内容都是直接根据3GPP整理,保证更新内容的准确性,避免通过二手,甚至多手的资料,以讹传讹误导网友. 在介绍完流程详解后,会整理专 ...

  8. 4G与5G会话建立流程描述以及对比

    4G与5G会话建立流程描述以及对比 1. 用于会话建立流程的EPC网元与5GC网元 1.1 EPC架构 1.2 5GC架构 1.3 有关会话建立流程中网络功能分离的描述 2. EPC与5GC会话建立信 ...

  9. PHP写的电视直播插件实例创建流程

    PHP写的电视直播插件实例创建流程 这是最近写的一个PHP电视直播插件实例. 作者:G.FLOWER 主页:https://wdc.store 目录结构: 创建zb目录,可放在网站二级目录 创建zby ...

最新文章

  1. Android:dagger2让你爱不释手-基础依赖注入框架篇
  2. 算法 求两个自然数的最小公倍数 C
  3. 十三、流程控制之if语句
  4. 【Java线程】深入理解Volatile关键字和使用
  5. Web前端开发最佳实践(3):前端代码和资源的压缩与合并
  6. 谷歌搜索363搜索引擎入口_SEO谷歌搜索引擎优化到底有啥好?
  7. C语言:求圆的面积和周长
  8. 《javascript高级程序设计》读书笔记——作用域
  9. CDH 5.13.0安装方法
  10. 重庆市谷歌卫星地图下载
  11. 00003__位图简介
  12. JAVA - 银行卡认证
  13. Error: Getter not found: 'suspending'. case AppLifecycleState.suspending
  14. 【狂神说Java】Spring Boot笔记
  15. LeetCode精选TOP面试题(中等篇)【出现率降序】
  16. 商城项目实战24:实现添加商品功能
  17. Unity 之 ShaderGraph Channel节点解析汇总
  18. 在ReactJS中正确修改状态数组
  19. SAP中重复制造生产计划编制——机器工时计算
  20. 非常优秀的网站设计案例,设计师必备

热门文章

  1. angularjs2使用magnifier图片展示插件
  2. urllib库用POST请求模仿有道在线翻译
  3. 基于Android课堂学习系统的文献综述
  4. 白鹭科技挂牌新三板 连续三年亏损
  5. java计算机毕业设计线上订餐系统MyBatis+系统+LW文档+源码+调试部署
  6. c语言课程设计湖南工程学院,湖南工程学院15级C语言课程设计报告.doc
  7. net start mysql 提示:发生系统错误 2。 系统找不到指定的文件。
  8. 什么是浮动塌陷css,CSS浮动塌陷和一点关于浮动的事儿
  9. 关于数字石油,为什么智慧油田能拉动产业变革?
  10. 46家著名公司的技术类笔试真题