当前位置: 首页 > 后端技术 > Node.js

php+nodeJs+thrift协议实现zookeeper节点数据自动发现

时间:2023-04-03 22:33:28 Node.js

php是目前最流行的web服务器端语言,zookeeper是一个大规模的分布式协同工具。本文介绍一种实现PHP服务器响应zookeeper数据变化的架构自动监控一、问题背景PHP可以通过CLI方式连接zookeeper(以下简称zk),实现zk节点数据的自动发现,不会在这里描述。但是在web服务器中,PHP只能主动连接zk获取节点数据,并不能自动发现zk数据。其次,phpweb服务也很难与phpCLI模式下的服务共享数据变量(zk数据在cli模式下做成共享变量)。这就导致如果并发量大,每次http请求php都会连接zk,zk集群的压力会很大。其次,每次请求都会连接zk,请求完成后会释放zk连接。zk的连接和释放太频繁了。2、解决思路NodeJs可以实现多进程间通信,可以解决PHP服务难以实现共享变量的问题。nodeJs可以在主进程中抛出一个子进程,在子进程中实现zk的自动发现。当子进程检测到zk节点的数据变化时,会主动通知主进程。节点主进程写一个服务对外提供zk数据。当phpweb服务需要zk节点数据时,通过RPC协议(这里使用thrift协议)访问本地节点主进程服务,获取zk节点数据。这样有3个好处:1.实现zk节点变化的自动发现;2.PHP与node在同一台服务器上通信,无需网管,速度快,稳定可靠3.Thrift协议直接操作sockets传输数据,速度比http服务快,大致可以看成是php的方法调用自己。三、具体实现1、搭建zookeeper服务。这里我搭建了一个5个zk服务的伪集群(zk服务的搭建这里就不过多介绍了),测试zk服务能否正常读写节点数据分别启动5个zk服务器/server001/bin/zkServer.sh启动。/server002/bin/zkServer.sh启动。/server003/bin/zkServer.sh启动。/server004/bin/zkServer.shstart./server005/bin/zkServer.shstart!【zookeeper集群启动】[1]启动成功后,测试节点是否可以正常读写(创建一个/zk_test节点提前)启动zk客户端。/bin/zkCli.sh/zk_testtestwriting123:set/zk_test123发现可以正常读写了![zk写入和读取][2]2.创建节点服务定义thrift提供的服务,新建一个thrift文件,定义返回zk数据的服务:zkDataService,服务中有一个返回节点数据命名空间php的方法zkDatatutorialservicezkDataService{stringzkData()}根据thrift协议生成server端和client端中间代码(生成中间代码我把代码放在windows上完成),C:\Users\77388\AppData\thrift-0.10.0.exe-r--genjs:nodezkData.thrift此时会在文件夹中生成中间代码,在gen-nodejs文件夹中!【生成node端中间代码】[3]node安装zookeeper模块:cnpm安装node-zookeeper-client,写入子进程support.js,自动发现zk节点数据变化console.log('pidinworker:',process.pid);过程。上('混乱age',function(msg){console.log('3:',msg);});vari=0;varzookeeper=require('node-zookeeper-client');varclient=zookeeper.createClient('localhost:2181');varpath='/zk_test';//节点名functiongetData(client,path){client.getData(path,function(event){console.log('Gotevent:%s',event);getData(client,path);},function(error,data,stat){if(error){console.log('获取数据时出错:%s.',error);return;}process.send('zookeepernodedata'+data.toString('utf8'));//通知主进程zk节点数据});}client.once('connected',function(){console.log('ConnectedtoZooKeeper.');getData(客户端,路径);});client.connect();process.emit('消息','=======');编写主进程server.js实现thrift定义的服务,并在主进程中启动子进程varchildprocess=require('child_process');varworker=childprocess.fork('./support.js');console。log('master中的pid:',process.pid);varchildMessage="";//监听子进程事件worker.on('message',function(msg){childMessage=msg;console.log('1:',msg);//ListenSubprocesszkdata,andprintzknodedata})process.on('message',function(msg){console.log('2:',msg);})worker.send('mainprocesstosubprocess传递的数据');//触发事件messageprocess.emit('message','------');varthrift=require("thrift");varzkDataService=require("./gen-nodejs/zkDataService");varttypes=require("./gen-nodejs/tutorial_types");vardata={};varserver=thrift.createServer(zkDataService,{zkData:function(result){result(null,childMessage);//返回zk节点数据}});服务器.listen(9090);启动nodeJs主进程:nodeserver.js3。创建一个php服务,在php服务中也生成一个thrift中间件程序,和node端类似,php调用node主进程server.js的zkData方法获取zk节点数据registerNamespace('Thrift',__DIR__.'/lib');$loader->registerDefinition('shared',$GEN_DIR);$loader->registerDefinition('tutorial',$GEN_DIR);$loader->register();/**根据一个*或多个贡献者许可协议授权给Apache软件基金会(ASF)。有关版权所有权的更多信息,请参阅随本作品分发的通知文件*。ASF根据Apache许可证2.0版(“许可证”)向您许可此文件*;除非符合*许可证,否则您不得使用此文件。您可以在**http://www.apache.org/licenses/LICENSE-2.0获得许可证的副本**除非适用法律要求或书面同意,*根据许可证分发的软件在*“按原样”为基础,不提供任何*种类的明示或暗示的保证或条件。请参阅*特定语言g的许可证许可证下的支配权限和限制*。*/使用Thrift\Protocol\TBinaryProtocol;使用Thrift\Transport\TSocket;使用Thrift\Transport\THttpClient;使用Thrift\Transport\TBufferedTransport;使用Thrift\Exception\TException;try{if(array_search('--http',$argv)){$socket=newTHttpClient('localhost',8080,'/php/PhpServer.php');}else{$socket=newTSocket('192.168.0.105',9090);}$transport=newTBufferedTransport($socket,1024,1024);$protocol=newTBinaryProtocol($transport);$client=new\tutorial\zkDataServiceClient($protocol);$运输->打开();$result=$client->zkData();print"$result";//打印zk节点数据$transport->close();}catch(TException$tx){print'TException:'.$tx->getMessage()."\n";}?>启动php服务,发现zk数据正常获取,修改zookeeper数据。启动php服务后,发现可以自动发现。总结:至此php和nodeJS协同完成php服务的zk数据自动发现完成。该架构的总体思路是node子进程实现zk的自动发现,node主进程维护一个zk节点数据的共享变量。当其他服务要使用zk节点数据时,从节点主进程获取。