迹忆博客
当前位置: 主页 > 学无止境 > 编程语言 > 文章

php zookeeper常见问题解决方案

发布时间: 2017-03-13 作者: 迹忆 浏览次数:

《PHP Zookeeper你需要知道的细节》(以下称为php_zk)一章中我们提出了问题,并且通过分析PHP-ZooKeeper源码找出了问题的原因,但是并没有给出解决方法。本章我们就来看一看解决的办法。

解决的办法分为两种:

一是修改PHP-ZooKeeper源码,重新编译安装
二是修改php代码

下面我们先来看第一种方式。

修改PHP-ZooKeeper源码

在php_zk一章中我们看到,其实在znode节点值为NULL的时候,使用php-zookeeper的get()方法能监听znode节点,但是并不能成功调用回调函数。原因就在于get()这个函数底层实现是当znode值为null的时候调用的函数如下

status = zoo_exists(i_obj->zk, path, 1, &stat);

但是我们可以看一下当znode有值的时候,它会调用到下面的函数

status = zoo_wget(i_obj->zk, path, (fci.size != 0) ? php_zk_watcher_marshal : NULL,
	          cb_data, buffer, &length, &stat);

所以我们分析php_zk_watcher_marshal是解析回调函数的,而在zoo_exists()中第三个参数为1,因此要想解决问题,必须要在zoo_exists()这个函数上找突破。继续进入zoo_exists()函数底层的定义发现其实该函数的实现也很简单

int zoo_exists(zhandle_t *zh, const char *path, int watch, struct Stat *stat)
{              
    return zoo_wexists(zh,path,watch?zh->watcher:0,zh->context,stat);
}

在它的底层又调用了zoo_wexists()函数。所以说我们完全可以在get()函数定义中将zoo_exists()函数改成zoo_wexists()。示例如下

if (max_size <= 0) {
    /*status = zoo_exists(i_obj->zk, path, 1, &stat);*/
    status =zoo_wexists(i_obj->zk,path,(fci.size!=0)?php_zk_watcher_marshal:NULL,cb_data,&stat);
    if (status != ZOK) {
	php_cb_data_destroy(&cb_data);
	php_error_docref(NULL TSRMLS_CC, E_WARNING, "error: %s", zerror(status));
	return;

    }
    length = stat.dataLength;
} else {
    length = max_size;
}

这样一来,回调函数就会被执行了。

保存以后,重新编译安装就可以了

# ./configure --with-libzookeeper-dir=/opt/zk_c/ --with-php-config=/usr/local/php5/bin/php-config
# make
# make test
# make install

因为之前已经在php.ini中添加了zookeeper的配置,所以这里不用在进行任何配置。

完成以后再次按照php_zk文章中进行php代码的运行步骤就会发现能正常的进行新的leader的选举了。

修改php代码

虽然能修改PHP-ZooKeeper的源码来解决问题,但是没有十足的把握还是不要修改源码,因为这可能会影响到其它函数的使用。所以这里我们可以在php代码层来进行修改。

我们在php_zk一章中看到,在进行/cluster子节点的创建中使用的是下面的代码

$this->znode = $this->create(self::CONTAINER . '/w-', null, $this->acl, Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE);

在$this->create()函数中,第三个参数是znode的值,这里我们默认为null。如果我们给他一个不为null的默认值的话,这个问题就迎刃而解了。如下示例

$this->znode = $this->create(self::CONTAINER . '/w-', '1', $this->acl, Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE);

当然我们这里为了测试,只是简单的给了一个1。在实际场景中在创建节点的时候会根据实际应用来给出默认值,这里就暂且使用1来测试。

修改以后再次按照之前的步骤运行——不用在zookeeper客户端单独进行值的设置——就会发现也是能重新选出leader的。

以上两种方式我都是经过代码测试的,实践证明其可行。但是在实际中应该怎样去使用PHP-ZooKeeper都要根据场景去定。我这里只是抛砖引玉,指出在学习中的一些问题,希望能帮到各位。

赞助
迹忆博客

除非注明转载,本站文章均为原创,欢迎转载,转载请以链接形式注明出处

本文地址: