背景与目的

Zookeeper开发过程中遇到一些常见问题,为了后续开发不犯同样的错误,总结一下此类问题,并进行分析和解决。

适合人员

主要适合zookeeper开发、测试及运维相关人员。

问题与解决

一、 关于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。

 
 
 
 
 
 

C

 
1
2
3
4
5
6
7
8
9
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基本上所有的时间都是这个时间的整数倍。

四、 zoo_get_children内存泄露问题

问题描述:

调用zoo_get_children函数出现内存泄露问题。

问题分析:

通过查看代码发现问题在于 ZOOAPI int zoo_get_children(zhandle_t *zh, const char *path, int watch,struct String_vector *strings), 该API中String_vector *strings结构体定义如下:

 
 
 
 
 
 

C

 
1
2
3
4
5
struct String_vector
{
    int32_t count;
    char * *data;
};

Zookeeper API将getchildren结果通过String_vector结构体返回时,malloc分配内存,将子节点所有目录存放在data中,而释放内存需要有客户端来做处理。

问题解决:

调用zoo_get_children(zh, path, watch, strings);需要通过调用zookeper提供的释放内存的方法:deallocate_String_vector(strings)。

 
 
 
 
 
 

C

 
1
2
3
4
5
6
7
8
9
10
11
12
13
int deallocate_String_vector(struct String_vector *v){
    if (v->data)
    {
        int32_t i;
        for(i = 0; i < v->count; i++)
        {
            deallocate_String(&v->data[i]);
        }
        free(v->data);
        v->data = 0;
    }
    return 0;
}

五、 如何正确设置和获取watcher

Watcher 设置是开发中最常见的,需要搞清楚watcher的一些基本特征,对于exists、getdata、getchild对于节点的不同操作会收到不同的 watcher信息。对父节点的变更以及孙节点的变更都不会触发watcher,而对watcher本身节点以及子节点的变更会触发watcher,具体参照下表。

操作 方法 触发watcher watcher state watcher type watcher path
Create当前节点 getdata × × × ×
getchildren 3 4
exists × × × ×
set当前节点 getdata 3 3
getchildren × × × ×
exists 3 3
delete当前节点 getdata 3 2
getchildren 3 2
exists 3 2
create子节点 getdata × × × ×
getchildren 3 4
exists × × × ×
set子节点 getdata × × × ×
getchildren × × × ×
exists × × × ×
delete子节点 getdata × × × ×
getchildren 3 4
exists × × × ×
恢复连接 getdata 1 -1 ×
getchildren 1 -1 ×
exists 1 -1 ×
恢复连接session未超时 getdata -112 -1 ×
getchildren -112 -1 ×
exists -112 -1 ×
恢复连接session超时 getdata 3 -1 ×
getchildren 3 -1 ×
exists 3 -1 ×
注: state = 2 表示删除事件;state = 3表示节点数据变更;state =4表示子节点事件;state = -1表示session事件。 type = -112表示session失效;type = 1表示session建立中;tpye = = 3表示session建立成功。×表示否,√表示是。

六、 zookeeper连接数问题

问题描述:

zookeeper服务器都运行正常,而客户端连接异常。

问题分析:

这是由于zookeeper client连接数已经超过了zookeeper server获取的配置最大连接数。所以导致zookeeper client连接失败。

解决方法:

修改zookeeper安装目录下 conf/zoo.cfg文件。将maxClientCnxns参数改成更大的值。

七、 zookeeper服务器安装相关问题

问题一:是否可以只装一个zookeeper服务器。

问题解答:

可以安装,此时没有leader,follow,此时zookeeper server状态为standalone。

./zkServer.sh status
JMX enabled by default
Using config: /home/bbs/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: standalone

关于zoo.cfg配置:

tickTime=2000initLimit=10
syncLimit=5
dataDir=../data
clientPort=4181

问题二:开发没有足够机器,一台机子上是否装三个zookeeper服务器集群。

问题解答:

这种安装模式只能说是一种伪集群模式。三个zookeeper服务器都安装在同一个服务器(platform)上,需保证clientPort不相同。
将zookeeper安装包分别解压在三个目录server1,server2,server3下,配置文件zoo.cfg
Server1配置文件 zoo.cfg,server1在data目录下增加文件myid内容为1。

dataDir=../datadata
LogDir=../dataLog
clientPort=5181
server.1=platform:5888:6888
server.2= platform:5889:6889
server.3= platform:5890:6890

Server2配置文件 zoo.cfg,server1在data目录下增加文件myid内容为2。

dataDir=../datadata
LogDir=../dataLog
clientPort=6181
server.1=platform:5888:6888
server.2= platform:5889:6889
server.3= platform:5890:6890

Server3配置文件 zoo.cfg,server1在data目录下增加文件myid内容为3。

dataDir=../datadata
LogDir=../dataLog
clientPort=7181
server.1=platform:5888:6888
server.2= platform:5889:6889
server.3= platform:5890:6890

Zookeeper开发常见问题的更多相关文章

  1. XBOX ONE游戏开发常见问题

    XBOX ONE游戏开发常见问题 终于弄懂这个在Unity的sdk在Account Picker切换账号的机制了,一个手柄注册一个账号,在游戏里面的时候,只有另外一个手柄选择自己的账号,系统的Acti ...

  2. Xamarin 开发常见问题

    原文:Xamarin 开发常见问题 Verify the project is selected to be deployed in the Solution Configuration Manage ...

  3. 【前端技术】web 开发常见问题--GET POST 区别

    web 开发常见问题--GET POST 区别   首先,get和post是什么? --两种 HTTP 请求方法:GET 和 POST HTTP Request Methods GET.POST 专业 ...

  4. ARKit从入门到精通(11)-ARKit开发常见问题及解决方案

    转载请注明出处:ARKit从入门到精通(11)-ARKit开发常见问题及解决方案 本文主要介绍ARKit开发过程中一些常见问题 1.ARKit框架无法导入问题 2.ARKit运行黑屏或者白屏问题:Un ...

  5. ZooKeeper学习之路 (四)ZooKeeper开发环境eclipse配置

    一.eclipse中配置zookeeper开发环境 1)将zookeeper eclipse plugin中的6个jar包放到eclipse安装目录下的plugins文件中,重启eclipse (2) ...

  6. 【小梅哥SOPC学习笔记】SOPC开发常见问题及解决办法集锦

    SOPC开发常见问题及解决办法集锦 一.Symbol 'NULL' could not be resolved 近期在评估使用NIOS II处理器进行项目的开发,我使用的软件是Quartus II 1 ...

  7. VueJS 开发常见问题集锦

    由于公司的前端开始转向 VueJS,最近开始使用这个框架进行开发,遇到一些问题记录下来,以备后用. 主要写一些 官方手册 上没有写,但是实际开发中会遇到的问题,需要一定知识基础. 涉及技术栈 CLI: ...

  8. Civil3D二次开发常见问题总结

    Civil3D二次开发常见问题总结 AutoCAD命令提示"未知命令**--"的原因:在Initialize方法内报出异常就会导致这种情况.O__O"-(或是少加了dll ...

  9. 【i.MX6UL/i.MX6ULL开发常见问题】单独编译内核,uboot生成很多文件,具体用哪一个?

    [i.MX6UL/i.MX6ULL开发常见问题]2.3单独编译内核,uboot生成很多文件,具体用哪一个? 答:内核编译出来的文件是~/MYiR-imx-Linux/arch/arm/boot/目录下 ...

随机推荐

  1. 数位DP || Gym 101653R Ramp Number

    每一位都大于等于前一位的数叫Ramp Number 给一个数,如果不是Ramp Number输出-1,如果是Ramp Number输出比它小的Ramp Number的个数 只和每一位上的数字有关 #i ...

  2. 欧拉函数 || LightOJ 1370 Bi-shoe and Phi-shoe

    给出x,求最小的y使y的欧拉函数大于等于x *解法:i).求出1e6之内的数的欧拉函数,遍历找             ii).求比x大的第一个质数——因为每个质数n的欧拉函数都是n-1 wa一次是因 ...

  3. java 数据库

    1.数据的概述 数据(data)是事实或观察的结果,是对客观事物的逻辑归纳,是用于表示客观事物的未经加工的的原始素材. 数据是信息的表现形式和载体,可以是符号.文字.数字.语音.图像.视频等.数据和信 ...

  4. Oracle中的DDL,DML,DCL总结

    转自http://blog.csdn.net/w183705952/article/details/7354974 DML(Data Manipulation Language,数据操作语言):用于检 ...

  5. Git Bash Windows客户端乱码

    最近升级Git后,打开Git Bash出现了乱码,解决方法是: 注意,我升级之后,本地和字符集栏位出现了空白的情况.如果检查这里为空白,那么把本地设置为zn_CN,字符集设置为UTF-8

  6. 自定义函数导致的sql性能问题

    同事说,某某报表跑的很慢,让我调查一下 优化前:该报表整体需要跑4小时以上. sql代码如下 SELECT /*省略多数查询字段*/ REP_FUN_REFCODEVALUE /*自定义函数*/ (P ...

  7. 条款23:宁一 non-member no-friend 替换member函数(prefer non-member non-friend functions to members functions)

    NOTE : 1.宁可拿non-member non-friend 函数替换member函数.这样做可以增加封装性/包裹单性(packaging flexibility)和机能扩展性.

  8. python 闭包&装饰器(一)

    一.闭包 1.举例 def outer(): x = 10 def inner(): # 内部函数 print(x) # 外部函数的一个变量 return inner # 调用inner()函数的方法 ...

  9. 数据结构实验1:C++实现静态顺序表类

    写了3个多小时,还是太慢了.太菜了! 图1 程序运行演示截图1 实验1 1.1 实验目的 熟练掌握线性表的顺序存储结构. 熟练掌握顺序表的有关算法设计. 根据具体问题的需要,设计出合理的表示数据的顺序 ...

  10. Python中input()和raw_input()函数的区别

    问题:在Python2.7中使用 input() 函数会出现 “NameError: Name ”***“ is not defined 的错误 解决: 使用raw_input() 函数,在Pytho ...