Zookeeper

简单介绍

Apache Zookeeper是开发和维护开源服务器的服务,它能够实现高度可靠的分布式协调。

安装Zookeeper(无需安装)

wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
tar zxvf zookeeper-3.4.10.tar.gz

安装Zookeeper C扩展支持

cd zookeeper-3.4.8/src/c
./configure --prefix=/usr/
make
make install

安装php的zookeeper扩展

wget https://pecl.php.net/get/zookeeper-0.6.2.tgz
tar zxvf zookeeper-0.6.2.tgz
cd zookeeper-0.6.2
phpize
./configure --with-libzookeeper-dir=/usr/
$ make
$ make install

启动zookeeper server

# {zookeeperserver}代表你zookeeper解压的目录mkdir -p /project/zookeeper/demo/data#zoo.conf 是默认启动所加载的配置文件
cp /{zookeeperserver}/conf/zoo_sample.cfg /{zookeeperserver}/conf/zoo.cfg/{zookeeperserver}/bin/zkServer start

zookeeper client 测试

/{zookeeperserver}/bin/zkCli.sh -server 127.0.0.1:2181# [zk: 127.0.0.1:2181(CONNECTED) x] 客户端连接信息shell
[zk: 127.0.0.1:2181(CONNECTED) 3] ls /
[zookeeper]
[zk: 127.0.0.1:2181(CONNECTED) 4] create /test qkl001
Created /test
[zk: 127.0.0.1:2181(CONNECTED) 5] create /zgq zgq002
Created /zgq
[zk: 127.0.0.1:2181(CONNECTED) 6] ls /
[zookeeper, test, zgq]
[zk: 127.0.0.1:2181(CONNECTED) 5] delete /zgq
Created /zgq
[zk: 127.0.0.1:2181(CONNECTED) 7] quit

PHP下实践

zookeeper类信息

Zookeeper — Zookeeper类-- Zookeeper::addAuth — 指定应用程序凭据-- Zookeeper::connect — 创建与Zookeeper沟通的句柄-- Zookeeper::__construct — 创建与Zookeeper沟通的句柄-- Zookeeper::create — 同步创建节点-- Zookeeper::delete — 同步删除Zookeeper中的一个节点-- Zookeeper::exists — 同步检查Zookeeper节点的存在性-- Zookeeper::get — 同步获取与节点关联的数据。-- Zookeeper::getAcl — 同步地获取与节点关联的ACL。-- Zookeeper::getChildren — 同步列出节点的子节点-- Zookeeper::getClientId — 返回客户端会话ID,仅在连接当前连接时才有效(即最后观察者状态为ZooOnCeleDelphi状态)-- Zookeeper::getRecvTimeout — 返回此会话的超时,如果连接当前连接(只有上次观察者状态为ZooOnCeleTytStand状态)才有效。此值可能在服务器重新连接后发生更改。-- Zookeeper::getState — 获取Zookeeper连接的状态-- Zookeeper::isRecoverable — 检查当前的Zookeeper连接状态是否可以恢复-- Zookeeper::set — 设置与节点关联的数据-- Zookeeper::setAcl — 同步设置与节点关联的ACL-- Zookeeper::setDebugLevel — 设置库的调试级别-- Zookeeper::setDeterministicConnOrder — 启用/禁用仲裁端点顺序随机化-- Zookeeper::setLogStream — 设置库用于日志记录的流-- Zookeeper::setWatcher — 设置观察函数

客户端操作

zkCli.cmd# output 表示连接成功
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0]# 以下是操作命令
ls /
create /ztest 1

获取节点信息(Zookeeper::get)

# get.php$zoo = new Zookeeper('192.168.1.45:2181');
$r = $zoo->get( '/ztest');
var_dump($r);

获取节点信息(Zookeeper::get)并设置watcher

# get.php
class ZookeeperDemo extends Zookeeper
{public function watcher($type, $state, $key){var_dump($type);var_dump($state);var_dump($key);if ($type == 3) {var_dump($this->get('/zgetw'));// Watcher gets consumed so we need to set a new one$this->get('/zgetw', array($this, 'watcher'));}}}$zoo = new ZookeeperDemo('192.168.1.45:2181');
$zoo->get('/zgetw', [$zoo, 'watcher']);while (true) {echo '.';sleep(1);
}

客户端操作

set /ztest 2
set /ztest 3
set /ztest 5

获取节点信息(Zookeeper::get) 结果

php get.php#output
......int(3)
int(3)
string(6) "/ztest"
string(1) "2"
..int(3)
int(3)
string(6) "/ztest"
string(1) "3"
..int(3)
int(3)
string(6) "/ztest"
string(1) "4"
.int(3)
int(3)
string(6) "/ztest"
string(1) "5"

创建子节点

create /ztest/child1 c1
# output: Created /ztest/child1create /ztest/child2 c2
# output: Created /ztest/child2ls /ztest
# output: [child2, child1]

php下获取子节点

# getChild.php
$zookeeper = new Zookeeper('192.168.1.45:2181');
$path = '/ztest';
$r = $zookeeper->getchildren($path);
if (!empty($r)) {foreach ($r as $c){var_dump($c);}
}# php getChild.php
string(6) "child2"
string(6) "child1"

创建顺序节点

[zk: localhost:2181(CONNECTED) 22] create /stest 1
Created /stest
[zk: localhost:2181(CONNECTED) 23] create -s /stest/seq 1
Created /stest/seq0000000000
[zk: localhost:2181(CONNECTED) 24] create -s /stest/seq 1
Created /stest/seq0000000001
[zk: localhost:2181(CONNECTED) 25] create -s /stest/seq 1
Created /stest/seq0000000002
[zk: localhost:2181(CONNECTED) 26] create -s /stest/seq 1
Created /stest/seq0000000003
[zk: localhost:2181(CONNECTED) 27] create -s /stest/seq 1
Created /stest/seq0000000004
[zk: localhost:2181(CONNECTED) 28] create -s /stest/seq 1
Created /stest/seq0000000005
[zk: localhost:2181(CONNECTED) 29] create -s /stest/seq 1
Created /stest/seq0000000006
[zk: localhost:2181(CONNECTED) 30] create -s /stest/seq 1
Created /stest/seq0000000007
[zk: localhost:2181(CONNECTED) 31] create -s /stest/seq 2
Created /stest/seq0000000008
[zk: localhost:2181(CONNECTED) 32] create -s /stest/seq 2
Created /stest/seq0000000009
[zk: localhost:2181(CONNECTED) 33] create -s /stest/seq 2
Created /stest/seq0000000010
[zk: localhost:2181(CONNECTED) 34] create -s /stest/seq 2
Created /stest/seq0000000011
[zk: localhost:2181(CONNECTED) 35] create -s /stest/seq 2
Created /stest/seq0000000012
[zk: localhost:2181(CONNECTED) 36] create -s /stest/seq 2
Created /stest/seq0000000013
[zk: localhost:2181(CONNECTED) 37] create -s /stest/seq 2
Created /stest/seq0000000014

代码

$zookeeper = new Zookeeper('192.168.1.45:2181');
$aclArray = array(array('perms'  => Zookeeper::PERM_ALL,'scheme' => 'world','id'     => 'anyone',)
);
$path = '/t3';
//ZOO_EPHEMERAL = 1
//ZOO_SEQUENCE  = 2
//这里这里的flag=NULL,flag=0 表示创建永久节点,=1创建临时节点,=2创建seq 顺序节点
$realPath = $zookeeper->create($path, null, $aclArray, 1);
var_dump($realPath);

worker

一个利用顺序临时节点的leader迁移实现

# worker.php
<?php/*** Created by PhpStorm.* User: qkl* Date: 2018/8/27* Time: 14:25*/
class Worker
{const CONTAINER = '/worker_test';protected $acl = [['perms' => Zookeeper::PERM_ALL,'scheme' => 'world','id' => 'anyone']];private $isLeader = false;private $znode = '';private $prevNode = '';public function __construct($host = '', $watcher_cb = null, $recv_timeout = 10000){$this->zk = new Zookeeper($host, $watcher_cb, $recv_timeout);}public function register(){if (!$this->zk->exists(self::CONTAINER)) {$this->zk->create(self::CONTAINER, null, $this->acl);}# 创建一个临时的顺序节点$this->znode = $this->zk->create(self::CONTAINER . '/w-',null,$this->acl,Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE);//获取顺序节点名,去除父路径$this->znode = str_replace(self::CONTAINER . '/', '', $this->znode);printf("我创建了节点: %s\n", self::CONTAINER . '/' . $this->znode);$this->prevNode = $this->getPrev();if (is_null($this->prevNode)) {$this->setLeader(true);} else {$this->zk->get(self::CONTAINER . "/" . $this->prevNode, [$this, 'watcher']);}}public function getPrev(){$workers = $this->zk->getChildren(self::CONTAINER);sort($workers);$size = count($workers);for ($i = 0; $i < $size; $i++) {if ($this->znode == $workers[$i] && $i > 0) {return $workers[$i - 1];}}return null;}public function watcher($type, $state, $key){$prevNode = $this->prevNode;printf("watchNode-getPrevious:%s\n", self::CONTAINER . "/" . $prevNode);if (!is_null($prevNode)) {if ($type == 2) {printf($prevNode . " had deleted\n");}if ($type == 3) {printf("我重新监控节点:%s\n", self::CONTAINER . "/" . $prevNode);$this->zk->get(self::CONTAINER . "/" . $prevNode, [$this, 'watcher']);}}}public function isLeader(){return $this->isLeader;}public function setLeader($flag){$this->isLeader = $flag;}public function run(){$this->register();while (true) {if ($this->isLeader()) {$this->leaderJob();} else {$this->watcherJob();}sleep(2);}}public function leaderJob(){echo "现在我是Leader\n";}public function watcherJob(){echo "我在监控:".(self::CONTAINER . "/" . $this->prevNode)."\n";}}$worker = new Worker('192.168.1.45:2181');
$worker->run();

尝试

# 终端1
php worker.php
# 终端2
php worker.php
# 终端3
php worker.php# 此处运行不会被节点变化不会被监控到

再次尝试

# zkCli
create /worker_test/w-
/worker_test/0000000020php worker.php# output
我创建了节点: /worker_test/w-0000000022
我在监控:/worker_test/w-0000000020
我在监控:/worker_test/w-0000000020
watchNode-getPrevious:/worker_test/w-0000000020
我重新监控节点:/worker_test/w-0000000020
我在监控:/worker_test/w-0000000020
我在监控:/worker_test/w-0000000020
我在监控:/worker_test/w-0000000020
我在监控:/worker_test/w-0000000020
我在监控:/worker_test/w-0000000020
watchNode-getPrevious:/worker_test/w-0000000020
我重新监控节点:/worker_test/w-0000000020
2018-08-28 02:11:46,684:2486(0x7f28ed0a1700):ZOO_WARN@zookeeper_interest@1570: Exceeded deadline by 15ms
我在监控:/worker_test/w-0000000020
我在监控:/worker_test/w-0000000020
watchNode-getPrevious:/worker_test/w-0000000020
w-0000000020 had deleted
我在监控:/worker_test/w-0000000020

这边发现一个类似bug问题

如果我们直接运行worker.php
在worker.php运行创建的临时顺序节点是不会被watcher到的
我们必须先首先创建好相关的节点再启动监控,不知道这里是不是php版本的zookeeper的bug
有了解的小伙伴可以告之下

Watcher通知状态与事件类型一览

ZOO_CREATED_EVENT(value=1):节点创建事件,需要watch一个不存在的节点,当节点被创建时触发,此watch通过zoo_exists()设置
ZOO_DELETED_EVENT(value=2):节点删除事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHANGED_EVENT(value=3):节点数据改变事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHILD_EVENT(value=4):子节点列表改变事件,此watch通过zoo_get_children()或zoo_get_children2()设置
ZOO_SESSION_EVENT(value=-1):会话事件,客户端与服务端断开或重连时触发
ZOO_NOTWATCHING_EVENT(value=-2):watch移除事件,服务端出于某些原因不再为客户端watch节点时触发

PHP和zookeeper结合实践相关推荐

  1. ZooKeeper场景实践:(6)集群监控和Master选举

    1. 集群机器监控 这通经常使用于那种对集群中机器状态,机器在线率有较高要求的场景,可以高速对集群中机器变化作出响应.这种场景中,往往有一个监控系统,实时检測集群机器是否存活. 利用ZooKeeper ...

  2. Zookeeper场景实践:(5)分布式通知/协调

    1.基本介绍 通知/协调机制通常有两种方式. 系统调度模式:操作人员发送通知实际是通过控制台改变某个节点的状态,然后Zookeeper将这些变化发送给注冊了这个节点的Watcher的全部client. ...

  3. EOSPlatform+Dubbo+Zookeeper最佳实践

    2019独角兽企业重金招聘Python工程师标准>>> 摘要:随着分布式服务框架的流行,许多公司都引入了业界流行的分布式服务框架,本文介绍如何使用EOSPlatform+Dubbo+ ...

  4. ZooKeeper的实践(一):ZooKeeper仲裁机制

    ZooKeeper仲裁机制 概述 仲裁 深入分析节点的数量问题 总结 概述 zk服务器运行模式分成两种: 独立模式 仲裁模式 如果是用独立模式(standalone),则zk的状态是无法进行复制的,这 ...

  5. 干掉 ZooKeeper,阿里为什么不用 ZK 做服务发现?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源 | https://urlify.cn/fIjYVb 站在未 ...

  6. 干掉 ZooKeeper?阿里为什么不用 ZK 做服务发现?

    -     前言    - 站在未来的路口,回望历史的迷途,常常会很有意思,因为我们会不经意地兴起疯狂的念头,例如如果当年某事提前发生了,而另外一件事又没有发生会怎样?一如当年的奥匈帝国皇位继承人斐迪 ...

  7. 说得太好了!阿里巴巴为什么不用 ZooKeeper 做服务发现?

    作者:坤宇 yq.aliyun.com/articles/601745?scm=20140722.184.2.173 站在未来的路口,回望历史的迷途,常常会很有意思,因为我们会不经意地兴起疯狂的念头, ...

  8. Hadoop安全实践

    前言 在2014年初,我们将线上使用的 Hadoop 1.0 集群切换到 Hadoop 2.2.0 稳定版, 与此同时部署了 Hadoop 的安全认证.本文主要介绍在 Hadoop 2.2.0 上部署 ...

  9. 好文荐读 | 阿里巴巴为什么不用 ZooKeeper 做服务发现?

    服务发现领域一篇比较有名的文章,之前已经转载过国外写的那篇 为什么不应该使用ZooKeeper做服务发现 文章来源:https://developer.aliyun.com/article/60174 ...

  10. Zookeeper介绍、原理及应用

    Zookeeper简介 Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理 ...

最新文章

  1. 第十二课.统计推断的基本思想
  2. CSharpGL(19)用glReadPixels把渲染的内容保存为PNG图片(C#)
  3. source insight使用说明[转]--后续发现好的再加
  4. LSP(分层服务提供者)
  5. 程序员如何用糖果实现盈利 - [别人家的程序员01]
  6. C语言实用算法系列之学生管理系统_单向链表内操作_选择排序
  7. 3d制作中需要注意的问题_珠宝首饰工艺篇-戒指3D造型设计制作注意要点
  8. Linux保护线程,linux的线程是否受到了保护?
  9. Oracle 11g Dataguard 物理备库配置(三)之Dataguard broker配置
  10. 如何在C#中生成与PHP一样的MD5 Hash Code
  11. Java实现简易的文本编辑器
  12. 火狐浏览器Json插件(JSONView)
  13. 机器学习——DBN深度信念网络详解
  14. 【电子签章】HTML格式合同转化成PDF文件
  15. 电驴v1.2.2.45574最新版官方下载
  16. 用JSON-server模拟REST API(二) 动态数据
  17. 前端:标准删除确认提示
  18. 华为服务器开虚拟化,华为服务器虚拟化的随笔
  19. 密码校验:大小写字母、字符、数字组合,最少8位
  20. Python代码使用easyocr识别身份证号码

热门文章

  1. 【Prison Break】第四天(3.31)
  2. 【OpenCV学习笔记】【函数学习】十四(cvSeq的用法说明(功能很多,按照需求使用))
  3. GCC图神经网络预训练概述
  4. 英文字母信息熵与冗余度计算Python实现
  5. 从零基础入门Tensorflow2.0 ----七、35. 文本生成之---1.数据处理
  6. 模板题——质数、素数、约数
  7. oracle在线重定义表分区,oracle把一张表在线重定义成分区表
  8. 中内连和外联的去区别_外联请客丨第一百七十四期:鱼来了铁板烧请你吃铁板烤鱼和香辣牛蛙虾!...
  9. 四川大学计算机应用基础第二次作业,四川大学川成教2017年秋季《计算机应用基础》第二次作业...
  10. 蚂蚁员工人均都能买1套杭州的房子了?!好后悔,当初错失了蚂蚁...