php分布式开发认识,PHP ZooKeeper分布式应用开发

ZooKeeper是一个中心化服务,用于分布式应用下的配置同步和协调,提供统一配置服务,统一命名服务,分布式同步,集群管理等。Zookeeper 从设计模式角度来看,是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的那些观察者做出相应的反应。ZooKeeper的应用场景包括:统一命名服务;配置管理;集群管理;队列管理等。

ZooKeeper作为一个Java应用程序,有大神开发了PHP的扩展:php-zookeeper。利用ZooKeeper,我们可以让分布式的PHP应用程序协调产生leader,为woker分配任务,当leader崩溃时,自动选举产生leader;也可以作分布式的锁和队列。

ZooKeeper本身是一个集群,至少需要表示3台,只要超过半数节点正常就可以工作,避免单点故障。首先需要安装JDK环境

yum search java | grep 'java-'

sudo yum install java-1.8.0-openjdk-devel

然后安装ZooKeeper,从官网下载

tar zxfv zookeeper-3.4.6.tar.gz

cd zookeeper-3.4.6/src/c

./configure --prefix=/usr/

make

sudo make install

#创建libzookeeper.conf,内容为/usr/lib,以便编译扩展使用

sudo vim /etc/ld.so.conf.d/libzookeeper.conf

#使配置生效

sudo ldconfig

然后安装PHP的扩展

cd

git clone https://github.com/andreiz/php-zookeeper.git

cd php-zookeeper

phpize

./configure

make

sudo make install

更改php.ini配置,增加以下内容

[zookeeper]

extension = zookeeper.so

查看是否加载成功

php -m | grep zookeeper

更改ZooKeeper配置,可以改变里面的DataDir熟悉,默认在/tmp下面

cp conf/zoo_sample.cfg conf/zoo.cfg

vim conf/zoo.cfg

然后终端A里面运行ZooKeeper,通过shell进行交互

cd zookeeper-3.4.6/bin

./zkServer.sh start

./zkCli.sh -server 127.0.0.1:2181

create /test hello

;Created /test

ls /

;[test, zookeeper]

这时便已成功连到了ZooKeeper,并创建了一个名为“/test”的znode。ZooKeeper以树形结构保存数据。这很类似于文件系统,但“文件夹”又和文件很像。znode是ZooKeeper保存的实体。

新建一个PHP脚本来测试一下

class ZookeeperDemo extends Zookeeper {

public function watcher( $i, $type, $key ) {

echo "Insider Watcher\n";

// Watcher gets consumed so we need to set a new one

$this->get( '/test', array($this, 'watcher' ) );

}

}

$zoo = new ZookeeperDemo('127.0.0.1:2181');

$zoo->get( '/test', array($zoo, 'watcher' ) );

while( true ) {

echo '.';

sleep(2);

}

在新的终端B里面运行这个脚本

$ php zookeeperdemo1.php

返回刚才的那个终端A里面,改变节点“/test”存储的数据

set /test world

这时候在终端B里面变化打印“Insider Watcher”。注意:这里注册的回到函数仅支持对象的方法,不支持普通的函数。

前面说过,ZooKeeper是一个基于观察者模式设计的分布式服务管理框架。Zookeeper提供了绑定在znode上的监听器,一旦监听到znode数据发生变化,便会通知所有注册的客户端。所以也可以应用于发布订阅模式。

这篇文章还举例,如何让多个PHP脚本自动选举leader,分配工作。

class Worker extends Zookeeper {

const CONTAINER = '/cluster';

protected $acl = array(

array(

'perms' => Zookeeper::PERM_ALL,

'scheme' => 'world',

'id' => 'anyone' ) );

private $isLeader = false;

private $znode;

public function __construct( $host = '', $watcher_cb = null, $recv_timeout = 10000 ) {

parent::__construct( $host, $watcher_cb, $recv_timeout );

}

public function register() {

if( ! $this->exists( self::CONTAINER ) ) {

$this->create( self::CONTAINER, null, $this->acl );

}

$this->znode = $this->create( self::CONTAINER . '/w-',

null,

$this->acl,

Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE );

$this->znode = str_replace( self::CONTAINER .'/', '', $this->znode );

printf( "I'm registred as: %s\n", $this->znode );

$watching = $this->watchPrevious();

if( $watching == $this->znode ) {

printf( "Nobody here, I'm the leader\n" );

$this->setLeader( true );

}

else {

printf( "I'm watching %s\n", $watching );

}

}

public function watchPrevious() {

$workers = $this->getChildren( self::CONTAINER );

sort( $workers );

$size = sizeof( $workers );

for( $i = 0 ; $i < $size ; $i++ ) {

if( $this->znode == $workers[ $i ] ) {

if( $i > 0 ) {

$this->get( self::CONTAINER . '/' . $workers[ $i - 1 ], array( $this, 'watchNode' ) );

return $workers[ $i - 1 ];

}

return $workers[ $i ];

}

}

throw new Exception(  sprintf( "Something went very wrong! I can't find myself: %s/%s",

self::CONTAINER,

$this->znode ) );

}

public function watchNode( $i, $type, $name ) {

$watching = $this->watchPrevious();

if( $watching == $this->znode ) {

printf( "I'm the new leader!\n" );

$this->setLeader( true );

}

else {

printf( "Now I'm watching %s\n", $watching );

}

}

public function isLeader() {

return $this->isLeader;

}

public function setLeader($flag) {

$this->isLeader = $flag;

}

public function run() {

$this->register();

while( true ) {

if( $this->isLeader() ) {

$this->doLeaderJob();

}

else {

$this->doWorkerJob();

}

sleep( 2 );

}

}

public function doLeaderJob() {

echo "Leading\n";

}

public function doWorkerJob() {

echo "Working\n";

}

}

$worker = new Worker( '127.0.0.1:2181' );

$worker->run();

打开多个终端运行这个脚本。使用Ctrl+c或其他方法退出第一个脚本。刚开始不会有任何变化,worker可以继续工作。后来,ZooKeeper会发现超时,并选举出新的leader。

除此之外,利用这个扩展还可以实现一下其他的应用场景,比如排他锁和共享锁:php-zookeeper-recipes。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值