PHP和zookeeper结合实践
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结合实践相关推荐
- ZooKeeper场景实践:(6)集群监控和Master选举
1. 集群机器监控 这通经常使用于那种对集群中机器状态,机器在线率有较高要求的场景,可以高速对集群中机器变化作出响应.这种场景中,往往有一个监控系统,实时检測集群机器是否存活. 利用ZooKeeper ...
- Zookeeper场景实践:(5)分布式通知/协调
1.基本介绍 通知/协调机制通常有两种方式. 系统调度模式:操作人员发送通知实际是通过控制台改变某个节点的状态,然后Zookeeper将这些变化发送给注冊了这个节点的Watcher的全部client. ...
- EOSPlatform+Dubbo+Zookeeper最佳实践
2019独角兽企业重金招聘Python工程师标准>>> 摘要:随着分布式服务框架的流行,许多公司都引入了业界流行的分布式服务框架,本文介绍如何使用EOSPlatform+Dubbo+ ...
- ZooKeeper的实践(一):ZooKeeper仲裁机制
ZooKeeper仲裁机制 概述 仲裁 深入分析节点的数量问题 总结 概述 zk服务器运行模式分成两种: 独立模式 仲裁模式 如果是用独立模式(standalone),则zk的状态是无法进行复制的,这 ...
- 干掉 ZooKeeper,阿里为什么不用 ZK 做服务发现?
点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源 | https://urlify.cn/fIjYVb 站在未 ...
- 干掉 ZooKeeper?阿里为什么不用 ZK 做服务发现?
- 前言 - 站在未来的路口,回望历史的迷途,常常会很有意思,因为我们会不经意地兴起疯狂的念头,例如如果当年某事提前发生了,而另外一件事又没有发生会怎样?一如当年的奥匈帝国皇位继承人斐迪 ...
- 说得太好了!阿里巴巴为什么不用 ZooKeeper 做服务发现?
作者:坤宇 yq.aliyun.com/articles/601745?scm=20140722.184.2.173 站在未来的路口,回望历史的迷途,常常会很有意思,因为我们会不经意地兴起疯狂的念头, ...
- Hadoop安全实践
前言 在2014年初,我们将线上使用的 Hadoop 1.0 集群切换到 Hadoop 2.2.0 稳定版, 与此同时部署了 Hadoop 的安全认证.本文主要介绍在 Hadoop 2.2.0 上部署 ...
- 好文荐读 | 阿里巴巴为什么不用 ZooKeeper 做服务发现?
服务发现领域一篇比较有名的文章,之前已经转载过国外写的那篇 为什么不应该使用ZooKeeper做服务发现 文章来源:https://developer.aliyun.com/article/60174 ...
- Zookeeper介绍、原理及应用
Zookeeper简介 Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理 ...
最新文章
- 第十二课.统计推断的基本思想
- CSharpGL(19)用glReadPixels把渲染的内容保存为PNG图片(C#)
- source insight使用说明[转]--后续发现好的再加
- LSP(分层服务提供者)
- 程序员如何用糖果实现盈利 - [别人家的程序员01]
- C语言实用算法系列之学生管理系统_单向链表内操作_选择排序
- 3d制作中需要注意的问题_珠宝首饰工艺篇-戒指3D造型设计制作注意要点
- Linux保护线程,linux的线程是否受到了保护?
- Oracle 11g Dataguard 物理备库配置(三)之Dataguard broker配置
- 如何在C#中生成与PHP一样的MD5 Hash Code
- Java实现简易的文本编辑器
- 火狐浏览器Json插件(JSONView)
- 机器学习——DBN深度信念网络详解
- 【电子签章】HTML格式合同转化成PDF文件
- 电驴v1.2.2.45574最新版官方下载
- 用JSON-server模拟REST API(二) 动态数据
- 前端:标准删除确认提示
- 华为服务器开虚拟化,华为服务器虚拟化的随笔
- 密码校验:大小写字母、字符、数字组合,最少8位
- Python代码使用easyocr识别身份证号码
热门文章
- 【Prison Break】第四天(3.31)
- 【OpenCV学习笔记】【函数学习】十四(cvSeq的用法说明(功能很多,按照需求使用))
- GCC图神经网络预训练概述
- 英文字母信息熵与冗余度计算Python实现
- 从零基础入门Tensorflow2.0 ----七、35. 文本生成之---1.数据处理
- 模板题——质数、素数、约数
- oracle在线重定义表分区,oracle把一张表在线重定义成分区表
- 中内连和外联的去区别_外联请客丨第一百七十四期:鱼来了铁板烧请你吃铁板烤鱼和香辣牛蛙虾!...
- 四川大学计算机应用基础第二次作业,四川大学川成教2017年秋季《计算机应用基础》第二次作业...
- 蚂蚁员工人均都能买1套杭州的房子了?!好后悔,当初错失了蚂蚁...