当前位置: 首页 > 后端技术 > PHP

Zookeeper的PHP实践

时间:2023-03-29 17:04:16 PHP

ApacheZookeeper是我最近接触到的最酷的技术,是在研究SolrCloud特性时发现的。Solr的分布式计算给我留下了深刻的印象。您只需要启动一个新实例,它就会自动在SolrCloud中找到。它会将自己分配给一个分片并确定它是领导者(源)还是副本。一段时间后,您将能够在您的那些服务器上进行查询。即使某些服务器出现故障,它也可以继续工作。非常有活力,聪明又酷。将多个应用程序作为一个逻辑程序运行并不是什么新鲜事。其实几年前我就写过类似的软件。这种体系结构令人困惑且使用起来费力。为此ApacheZookeeper提供了一套工具来管理这个软件。为什么叫动物园?“因为要协调的分布式系统是动物园”。在本文中,我将解释如何使用PHP安装和集成ApacheZooKeeper。我们将使用该服务来协调每个独立的PHP脚本,并让它们同意成为Leader(所谓的Leader选举)。当领导者退出(或崩溃)时,工作人员可以检测并选举新的领导者。ZooKeeper是一个中立的服务,用于管理配置信息、命名、提供分布式同步和组合服务。所有这些类型的服务都用于分布式应用程序。每次编写这些服务都涉及大量错误修复和竞争条件。由于编写这些服务的困难,它们通常被忽略,这使得当应用程序发生变化时很难管理应用程序。即使做得正确,实现这些服务的不同方法也会使部署应用程序变得难以管理。虽然ZooKeeper是一个Java应用程序,但也可以使用C。这里有一个PHP扩展,由AndreiZmievski在2009年创建和维护。您可以从PECL下载它,或者直接从GitHub获取PHP-ZooKeeper。要使用此扩展,您首先需要安装ZooKeeper。可以从官方网站下载。$tarzxfvzookeeper-3.4.8.tar.gz$cdzookeeper-3.4.8/src/c$./configure--prefix=/usr/$make$sudomakeinstall这将安装ZooKeeper的库和头文件.现在准备编译PHP扩展。$cd$gitclonehttps://github.com/andreiz/php-zookeeper.git$cdphp-zookeeper$phpize$./configure$make$sudomakeinstall添加“zookeeper.so”到PHP配置。vim/etc/php5/cli/conf.d/20-zookeeper.ini因为我不需要在web服务环境下运行,所以这里我只编辑CLI配置。将下面的行复制到ini文件中。extension=zookeeper.so使用以下命令判断扩展是否启用。$php-m|grepzookeeperzookeeper现在是运行ZooKeeper的时候了。唯一尚未完成的是配置。创建用于存放所有业务数据的目录。$mkdir/home/you-account/zoo$cd$cdzookeeper-3.4.5/$cpconf/zoo_sample.cfgconf/zoo.cfg$vimconf/zoo.cfg找到名为“dataDir”的属性,将其更改为指向“/home/you-account/zoo”目录。$bin/zkServer.shstart$bin/zkCli.sh-server127.0.0.1:2181[zk:127.0.0.1:2181(CONNECTED)14]create/test1Created/test[zk:127.0.0.1:2181(CONNECTED)19]ls/[test,zookeeper]至此,你已经成功连接到ZooKeeper并创建了一个名为“/test”的znode(我们稍后会用到它)。ZooKeeper以树状结构存储数据。这很像一个文件系统,但是“文件夹”(译者注:这里指的是非底层节点)类似于文件。znode是ZooKeeper保存的实体。Node(节点)这个词很容易混淆,所以为了避免混淆,这里使用了znode。因为我们稍后会用到它,所以这里我们保持客户端连接。打开一个新窗口并创建一个zookeeperdemo1.php文件。get('/test',array($this,'watcher'));}}$zoo=newZookeeperDemo('127.0.0.1:2181');$zoo->get('/test',array($zoo,'watcher'));while(true){echo'.';sleep(2);}现在运行脚本:$phpzookeeperdemo1.php这应该每2秒生成一个点。现在切换到ZooKeeper客户端并更新“/test”值。[zk:127.0.0.1:2181(CONNECTED)20]set/testfoo这将在PHP脚本中静默触发“InsiderWatcher”消息。怎么会这样?ZooKeeper提供可以绑定到znode的监视器。如果监视器检测到znode更改,该服务会立即通知所有相关客户端。这就是PHP脚本了解更改的方式。Zookeeper::get方法的第二个参数是回调函数。当事件触发时,监听器会被消耗掉,所以我们需要在回调函数中重新设置监听器。现在您已准备好创建分布式应用程序。挑战在于让这些独立的程序决定哪些(领导者)协调他们的工作,哪些(工人)需要执行。这个过程称为leader选举,相关实现方法参见ZooKeeperRecipesandSolutions。简单地说,每个进程(或服务器)都盯着相邻的进程(或服务器)。如果一个已经被监控的进程(也就是Leader)退出或者崩溃,监控程序会找它的相邻(此时最旧的)进程作为Leader。在实际应用中,leader给worker分配任务,监控进度并保存结果。为了简洁起见,我在这里跳过这些部分。创建一个新的PHP文件,命名为worker.php:Zookeeper::PERM_ALL,'scheme'=>'world','id'=>'anyone'));私人$isLeader=false;私人$znode;公共函数__construct($host='',$watcher_cb=null,$recv_timeout=10000){parent::__construct($host,$watcher_cb,$recv_timeout);}publicfunctionregister(){if(!$this->exists(self::CONTAINER)){$this->create(self::CONTAINER,null,$this->acl);}$this->znode=$this->create(self::CONTAINER.'/w-',null,$this->acl,Zookeeper::EPHEMERAL|动物园管理员::序列);$this->znode=str_replace(self::CONTAINER.'/','',$this->znode);printf("我注册为:%sn",$this->znode);$watching=$this->watchPrevious();if($watching==$this->znode){printf("这里没人,我是领导者");$this->setLeader(真);}else{printf("我在看%sn",$watching);}}publicfunctionwatchPrevious(){$workers=$this->getChildren(self::CONTAINER);排序($工人);$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'));返回$workers[$i-1];}返回$workers[$i];}}thrownewException(sprintf("出了点问题!我找不到自己了:%s/%s",self::CONTAINER,$this->znode));}publicfunctionwatchNode($i,$type,$name){$watching=$this->watchPrevious();if($watching==$this->znode){printf("我是新的领导者!n");$this->setLeader(真);}else{printf("现在我在看%sn",$watching);}}publicfunctionisLeader(){return$this->isLeader;}publicfunctionsetLeader($flag){$this->isLeader=$f落后;}publicfunctionrun(){$this->register();while(true){if($this->isLeader()){$this->doLeaderJob();}else{$this->doWorkerJob();}睡眠(2);}}publicfunctiondoLeaderJob(){echo"Leadingn";}publicfunctiondoWorkerJob(){echo"Workingn";}}$worker=newWorker('127.0.0.1:2181');$工人->运行();至少打开3个终端,并在每个终端中运行以下脚本:#term1$phpworker.php我注册为:w-0000000001这里没有人,我是leaderLeading#term2$phpworker.php我注册为:w-0000000002I'mwatchingw-0000000001Working#term3$phpworker.phpI'mregisteredas:w-0000000003I'mwatchingw-0000000002Working现在用Ctrl+c或者其他方法模拟Leader崩溃的情况退出第一个脚本。一开始不会有任何变化,工人可以继续工作。稍后,ZooKeeper将检测超时并选举新的领导者。虽然这些脚本很容易理解,但是有必要对使用的Zookeeper标志进行注释:$this->znode=$this->create(self::CONTAINER.'/w-',null,$this->acl,Zookeeper::短暂|动物园管理员::序列);每个znode都是EPHEMERAL和SEQUENCE。EPHEMRAL表示当客户端失去连接时删除znode。这就是PHP脚本知道超时的原因。SEQUENCE表示在每个znode名称后添加一个序列标识符。我们用这些唯一标识符标记工人。PHP部分还有一些问题需要注意。该插件目前还是测试版,如果使用不当,很容易出现segmentationfault。比如普通函数不能作为回调函数传入,必须是方法。希望PHP社区更多的同仁能够看到ApacheZooKeeper的好,扩展得到更多的支持。ZooKeeper是一款功能强大的软件,具有干净简单的API。有了好的文档和示例,任何人都可以轻松编写分布式软件。让我们开始吧,它会很有趣。

最新推荐
猜你喜欢