摘要:可以在主进程中抛出一个子进程,子进程中实现的自动发现,子进程侦察到节点数据变化时,主动通知主进程。架构的整体思路是子进程实现的自动发现,主进程维护一个节点数据的共享变量,其他服务要想使用节点数据时,从主进程中获取。
php是当下最流行的web服务器端语言,zookeeper是大型分布式协同工具,本文在这里介绍一种架构实现php服务器对于zookeeper数据变化的自动监听
一.问题背景
php可以CLI模式模式连接zookeeper(下面简称zk),并实现zk节点数据的自动发现,这里不做过多叙述。但web服务器中,php只能主动连接zk以获得节点数据,做不到zk数据的自动发现。其次,php web服务,也难以和php CLI模式下的服务共享数据变量(cli模式下zk数据做成共享变量)。这就导致如果并发量大的话,每一个http请求php都会去连接zk,zk集群的压力会很大,其次,每一个请求都会连接zk,请求结束又释放zk连接,zk的连接与释放过于频繁。
二.解决思路
nodeJs多进程间可以通信,可以解决php服务难以实现共享变量的问题。nodeJs可以在主进程中抛出一个子进程,子进程中实现zk的自动发现,子进程侦察到zk节点数据变化时,主动通知主进程。node主进程写一个服务,像外界提供zk的数据。php web服务需要zk节点数据时,通过RPC协议(这里使用thrift协议),访问本地node主进程服务,来获取zk节点数据。这样做有三点好处:1.实现zk节点变化的自动发现;
2.php和node通信在同一台服务器上,不走网管,速度快,稳定性可靠 3.thrift协议直接操作套接字传输数据,比http服务要快,可以近似看作php调用自己的方法
三.具体实现
1.搭建zookeeper服务,这里我搭了一个5台zk服务的伪集群(zk服务的搭建这里不做过多介绍),测试zk服务是否能正常写入与读取节点数据 分别启动五台zk服务器./server001/bin/zkServer.sh start ./server002/bin/zkServer.sh start ./server003/bin/zkServer.sh start ./server004/bin/zkServer.sh start ./server005/bin/zkServer.sh start ![zookeeper集群启动][1]
启动成功后,测试节点是否能够正常写入读取(这里提前创建了一个/zk_test节点) 启动zk客户端./bin/zkCli.sh /zk_test测试写入123:set /zk_test 123 发现可以正常写入与读取 ![zk写入与读取][2] 2.创建node服务 定义thrift提供的服务,新建thrift文件,定义返回zk数据的服务:zkDataService,服务中有一个方法zkData返回节点数据 namespace php tutorial service zkDataService { string zkData() } 根据thrift协议生成服务端可客户端的中间代码(生成中间代码我放在windows上完成),C:Users77388AppData hrift-0.10.0.exe -r --gen js:node zkData.thrift 此时会在文件夹中生成中间代码,在gen-nodejs文件夹中 ![生成node端中间代码][3] node安装zookeeper模块:cnpm install node-zookeeper-client,编写子进程support.js,自动发现zk节点数据变更
console.log("pid in worker:", process.pid); process.on("message", function(msg) { console.log("3:", msg); }); var i=0; var zookeeper = require("node-zookeeper-client"); var client = zookeeper.createClient("localhost:2181"); var path = "/zk_test";//节点名称 function getData(client, path) { client.getData( path, function (event) { console.log("Got event: %s", event); getData(client, path); }, function (error, data, stat) { if (error) { console.log("Error occurred when getting data: %s.", error); return; } process.send("zookeeper节点数据"+data.toString("utf8"));//通知主进程zk节点数据 } ); } client.once("connected", function () { console.log("Connected to ZooKeeper."); getData(client, path); }); client.connect(); process.emit("message", "======");
编写主进程server.js,实现thrift定义的服务,并在主进程中启动子进程
var childprocess = require("child_process"); var worker = childprocess.fork("./support.js"); console.log("pid in master:", process.pid); var childMessage=""; //监听子进程事件 worker.on("message", function(msg) { childMessage=msg; console.log("1:", msg);//监听子进程zk数据,并将zk节点数据打印 }) process.on("message", function(msg) { console.log("2:", msg); }) worker.send("主进程给子进程传递的数据"); //触发事件 message process.emit("message", "------"); var thrift = require("thrift"); var zkDataService = require("./gen-nodejs/zkDataService"); var ttypes = require("./gen-nodejs/tutorial_types"); var data = {}; var server = thrift.createServer(zkDataService, { zkData: function(result) { result(null, childMessage);//将zk节点数据返回 } }); server.listen(9090);
启动nodeJs主进程:node server.js
3.创建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(); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ use ThriftProtocolTBinaryProtocol; use ThriftTransportTSocket; use ThriftTransportTHttpClient; use ThriftTransportTBufferedTransport; use ThriftExceptionTException; try { if (array_search("--http", $argv)) { $socket = new THttpClient("localhost", 8080, "/php/PhpServer.php"); } else { $socket = new TSocket("192.168.0.105", 9090); } $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $client = new utorialzkDataServiceClient($protocol); $transport->open(); $result= $client->zkData(); print "$result";//打印zk节点数据 $transport->close(); } catch (TException $tx) { print "TException: ".$tx->getMessage()." "; } ?>
启动php服务,发现正常获取zk数据
修改zookeeper数据,在启动php服务,发现可以自动发现
总结:自此,php和nodeJS相协作,完成php服务对zk数据的自动发现就完成了。架构的整体思路是node子进程实现zk的自动发现,node主进程维护一个zk节点数据的共享变量,其他服务要想使用zk节点数据时,从node主进程中获取。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/25768.html
摘要:的服务治理平台发源于早期的个人项目。客户端发现模式要求客户端负责查询注册中心,获取服务提供者的列表信息,使用负载均衡算法选择一个合适的服务提供者,发起接口调用请求。系统和系统之间,少不了数据的互联互通。随着微服务的流行,一个系统内的不同应用进行互联互通也是常态。 PowerDotNet的服务治理平台发源于早期的个人项目Power.Apix。这个项目借鉴了工作过的公司的服务治理方案,站在...
摘要:等之所以支持跨语言,是因为他们自己定义了一套结构化数据存储格式,如的,用于编解码对象,作为各个语言通信的中间协议。 前段时间觉得自己一直用别人的框架,站在巨人的肩膀上,也该自己造造轮子了 一时兴起 就着手写起了RPC框架 这里写了系列博客拿给大家分享下 这篇是开篇的思路篇 项目最终的代码放在了我的github上https://github.com/wephone/Me... 欢迎sta...
摘要:启动容器,加载,运行服务提供者。服务提供者在启动时,在注册中心发布注册自己提供的服务。注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。 一 为什么需要 dubbo 很多时候,其实我们使用这个技术的时候,可能都是因为项目需要,所以,我们就用了,但是,至于为什么我们需要用到这个技术,可能自身并不是很了解的,但是,其实了解技术的来由及背景知识,对...
阅读 2683·2023-04-26 02:28
阅读 2479·2021-09-27 13:36
阅读 3094·2021-09-03 10:29
阅读 2710·2021-08-26 14:14
阅读 2067·2019-08-30 15:56
阅读 788·2019-08-29 13:46
阅读 2575·2019-08-29 13:15
阅读 407·2019-08-29 11:29