php安装zookeeper

php安装zookeeper

zookeeper是非常著名的分布式开源软件,在选主、配置管理、分布式锁等应用方面表现出色。那么在php环境下如何使用zookeeper呢?

zookeeper源码版本 zookeeper扩展版本
3.4.10 0.4.0

1.安装zookeeper Lib

首先需要下载zookeeper的源码进行编译安装,源码下载地址为为zookeeper源码

1
2
3
4
# tar -xzf zookeeper-3.4.10.tar.gz
# cd zookeeper-3.4.10/src/c
# ./configure –prefix=/usr/local/zookeeper-lib/
# make && make install

2.下载zookeeper扩展

官方下载地址:zookeeper扩展

1
2
3
4
5
6
7
# tar xzf zookeeper-0.4.0.tgz
# mv zookeeper-0.4.0 zookeeper
# cd zookeeper
# phpize
# ./configure -with-libzookeeper-dir=/usr/local/zookeeper-lib/
# make
# make install

如果phpize执行不下去,会提示安装php-devel,直接an’z
如果提示php-config错误,那么执行./configure的时候还需要指定-with-php-config(该值为你的php-config路径)

在php.ini的末尾增加

1
extension=zookeeper.so

然后执行

1
php -m | grep zookeeper

就可以看到扩展安装完成了。

3. 搭建集群

理论上集群的机器的个数为N(N为奇数且大于等于3,之所以需要奇数是因为需要多数派),下面我们有三台机器

机器名称 机器IP
A 101.101.101.1
B 101.101.101.2
C 101.101.101.3

3.1 复制配置文件

在A机器上面执行

1
cp /usr/local/zookeeper-3.4.10/conf/zoo_sample.cfg /usr/local/zookeeper-3.4.10/conf/zoo.cfg

3.2 编辑配置文件

然后编辑zoo.cfg如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/home/idonkeyliu/zoo

# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

server.0=101.101.101.0:2888:3888
server.1=101.101.101.1:2888:3888
server.2=101.101.101.2:2888:3888

3.3 创建节点ID

创建文件/home/idonkeyliu/zoo/myid/home/idonkeyliu/zoo目录为配置文件中的dataDir
然后将节点ID: 0写入到文件中。A机器的myid为0,B机器为1,C机器为2.与配置文件里面的server.X中的X一致。

3.4 拷贝配置文件与节点ID文件到其它机器

直接拷贝文件到B机器与C机器。

3.5 启动zookeeper

在A, B, C三台机器下面执行

1
/usr/local/zookeeper-3.4.10/bin]# ./zkServer.sh start

执行后看到如下提示表示启动成功

1
2
3
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

3.6 依次查看节点的状态

在A机器执行

1
/usr/local/zookeeper-3.4.10/bin]# ./zkServer.sh status

会显示

1
2
3
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: leader

表示A机器为zookeeper机器的主节点

在B与C机器执行

1
/usr/local/zookeeper-3.4.10/bin]# ./zkServer.sh status

会显示

1
2
3
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg
Mode: follower

表示B、C机器为zookeeper集群的从节点

4 zookeeper命令

ZooKeeper 支持某些特定的四字命令字母与其的交互。它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息。用户在客户端可以通过 telnet 或 nc 向 ZooKeeper 提交相应的命令。ZooKeeper常用四字命令见下表所示:

命令 作用
conf 输出相关服务配置的详细信息
cons 列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。包括“接受 / 发送”的包数量、会话 id 、操作延迟、最后的操作执行等等信息
dump 列出未经处理的会话和临时节点
envi 输出关于服务环境的详细信息(区别于 conf 命令)
reqs 列出未经处理的请求
ruok 测试服务是否处于正确状态。如果确实如此,那么服务返回“imok ”,否则不做任何相应
stat 输出关于性能和连接的客户端的列表
wchs 列出服务器 watch 的详细信息
wchc 通过 session 列出服务器 watch 的详细信息,它的输出是一个与watch 相关的会话的列表
wchp 通过路径列出服务器 watch 的详细信息。它输出一个与 session相关的路径

下面演示一下ruok命令

1
/usr/local/zookeeper-3.4.10/bin]# echo ruok | nc localhost 2181

然后会显示

1
imok

表示该节点处于正确状态。
如果nc命令执行不了,就执行yum install nmap-ncat安装

5 php脚本连接zookeeper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
<?php
/**
* PHP Zookeeper
*
* PHP Version 5.3
*
* The PHP License, version 3.01
*
* @category Libraries
* @package PHP-Zookeeper
* @author Lorenzo Alberton <l.alberton@quipo.it>
* @copyright 2012 PHP Group
* @license http://www.php.net/license The PHP License, version 3.01
* @link https://github.com/andreiz/php-zookeeper
*/

/**
* Example interaction with the PHP Zookeeper extension
*
* @category Libraries
* @package PHP-Zookeeper
* @author Lorenzo Alberton <l.alberton@quipo.it>
* @copyright 2012 PHP Group
* @license http://www.php.net/license The PHP License, version 3.01
* @link https://github.com/andreiz/php-zookeeper
*/
class Zookeeper_Example
{
/**
* @var Zookeeper
*/
private $zookeeper;

/**
* @var Callback container
*/
private $callback = array();

/**
* Constructor
*
* @param string $address CSV list of host:port values (e.g. "host1:2181,host2:2181")
*/
public function __construct($address) {
$this->zookeeper = new Zookeeper($address);
}

/**
* Set a node to a value. If the node doesn't exist yet, it is created.
* Existing values of the node are overwritten
*
* @param string $path The path to the node
* @param mixed $value The new value for the node
*
* @return mixed previous value if set, or null
*/
public function set($path, $value) {
if (!$this->zookeeper->exists($path)) {
$this->makePath($path);
$this->makeNode($path, $value);
} else {
$this->zookeeper->set($path, $value);
}
}

/**
* Equivalent of "mkdir -p" on ZooKeeper
*
* @param string $path The path to the node
* @param string $value The value to assign to each new node along the path
*
* @return bool
*/
public function makePath($path, $value = '') {
$parts = explode('/', $path);
$parts = array_filter($parts);
$subpath = '';
while (count($parts) > 1) {
$subpath .= '/' . array_shift($parts);
if (!$this->zookeeper->exists($subpath)) {
$this->makeNode($subpath, $value);
}
}
}

/**
* Create a node on ZooKeeper at the given path
*
* @param string $path The path to the node
* @param string $value The value to assign to the new node
* @param array $params Optional parameters for the Zookeeper node.
* By default, a public node is created
*
* @return string the path to the newly created node or null on failure
*/
public function makeNode($path, $value, array $params = array()) {
if (empty($params)) {
$params = array(
array(
'perms' => Zookeeper::PERM_ALL,
'scheme' => 'world',
'id' => 'anyone',
)
);
}
return $this->zookeeper->create($path, $value, $params);
}

/**
* Get the value for the node
*
* @param string $path the path to the node
*
* @return string|null
*/
public function get($path) {
if (!$this->zookeeper->exists($path)) {
return null;
}
return $this->zookeeper->get($path);
}

/**
* List the children of the given path, i.e. the name of the directories
* within the current node, if any
*
* @param string $path the path to the node
*
* @return array the subpaths within the given node
*/
public function getChildren($path) {
if (strlen($path) > 1 && preg_match('@/$@', $path)) {
// remove trailing /
$path = substr($path, 0, -1);
}
return $this->zookeeper->getChildren($path);
}

/**
* Delete the node if it does not have any children
*
* @param string $path the path to the node
*
* @return true if node is deleted else null
*/

public function deleteNode($path)
{
if(!$this->zookeeper->exists($path))
{
return null;
}
else
{
return $this->zookeeper->delete($path);
}
}

/**
* Wath a given path
* @param string $path the path to node
* @param callable $callback callback function
* @return string|null
*/
public function watch($path, $callback)
{
if (!is_callable($callback)) {
return null;
}

if ($this->zookeeper->exists($path)) {
if (!isset($this->callback[$path])) {
$this->callback[$path] = array();
}
if (!in_array($callback, $this->callback[$path])) {
$this->callback[$path][] = $callback;
return $this->zookeeper->get($path, array($this, 'watchCallback'));
}
}
}

/**
* Wath event callback warper
* @param int $event_type
* @param int $stat
* @param string $path
* @return the return of the callback or null
*/
public function watchCallback($event_type, $stat, $path)
{
if (!isset($this->callback[$path])) {
return null;
}

foreach ($this->callback[$path] as $callback) {
$this->zookeeper->get($path, array($this, 'watchCallback'));
return call_user_func($callback);
}
}

/**
* Delete watch callback on a node, delete all callback when $callback is null
* @param string $path
* @param callable $callback
* @return boolean|NULL
*/
public function cancelWatch($path, $callback = null)
{
if (isset($this->callback[$path])) {
if (empty($callback)) {
unset($this->callback[$path]);
$this->zookeeper->get($path); //reset the callback
return true;
} else {
$key = array_search($callback, $this->callback[$path]);
if ($key !== false) {
unset($this->callback[$path][$key]);
return true;
} else {
return null;
}
}
} else {
return null;
}
}
}


$zk = new Zookeeper_Example('A:2181,B:2181,C:2181');
var_dump($zk->get('/'));
var_dump($zk->getChildren('/'));
var_dump($zk->set('/test12345699999', 'abc'));
var_dump($zk->get('/test12345699999'));
var_dump($zk->getChildren('/'));

var_dump($zk->set('/foo1314567/001', 'bar1'));
var_dump($zk->set('/foo1314567/002', 'bar2'));
var_dump($zk->getChildren('/foo'));

//watch example
function callback() {
echo "in watch callback\n";
}
$zk->set('/brar111', 1);
$ret = $zk->watch('/brar111', 'callback');
$zk->set('/brar111', 2);
while (true) {
sleep(1);
zookeeper_dispatch();
}