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

服务治理深入浅出(二)——远程方法调用的实现

时间:2023-03-29 14:37:22 PHP

需求在了解了我们前面提到的服务治理的必要性之后。我们知道服务治理是基于很多“服务”的,所以第一步就是打通这些服务,也就是我们常说的RPC远程调用。像调用本地方法一样调用远程服务器上的方法。现在简单通俗地介绍一个需求:在A服务器部署的项目中,有一个UserService,方法是getUserInfo。如果我想在B服务器上“直接”调用这个方法怎么办?分析下面以PHP为例进行分析。我们希望在服务器B上实现一个类似服务器A的直接调用方式$userService=newUserService();$userService->getUserInfo($uid);我们经常使用SDK来调用第三方提供的API服务。我们的方法当然是类似$client=new\SDK\Client();$request=new\SDK\UserService\Request\GetStudentInfoRequest();$request->setUid($uid);$request->setMethod("GET");$response=$client->doAction($request);sdk中的GetStudentInfoRequest通过http映射服务器A上的UserService::getUserInfo。我们只需要在原来的基础上稍微修改一下sdk即可。以下代码只是一个简单的演示服务器。服务部署在localhost:8081classUserService{publicstaticfunctiongetUserInfo($uid){//假设以下内容从数据库中取出return['id'=>$uid,'username'=>'mengkang',];}}$service=$_GET['service'];$action=$_GET['action'];$argv=file_get_contents("php://input");if(!$service||!$action){die();}if($argv){$argv=json_decode($argv,true);}$res=call_user_func_array([$service,$action],$argv);回声json_encode($res);客户端类Client{private$url;私人服务;private$rpcConfig=["UserService"=>"http://127.0.0.1:8081",];/***客户端构造函数。*@param$service*/publicfunction__construct($service){if(array_key_exists($service,$this->rpcConfig)){$this->url=$this->rpcConfig[$service];$this->service=$service;}}公共函数__call($action,$arguments){$content=json_encode($arguments);$options['http']=['timeout'=>5,'method'=>'POST','header'=>'Content-type:application/x-www-form-urlencoded','content'=>$内容,];$context=stream_context_create($options);$get=['service'=>$this->service,'action'=>$action,];$url=$this->url。“?”.http_build_query($get);$res=file_get_contents($url,false,$context);返回json_decode($res,true);}}$userService=newClient('UserService');var_export($userService->getUserInfo(103));像本地一样在客户端调用远程方法不是很方便吗?这也是鸟哥@Laruenceyar的操作原理对比一下Yar的demo:Yar演示yarhttps://github.com/laruence/yaryar的java客户端https://github.com/zhoumengka...客户端代码,假设服务位于局域网10.211.55.4上层RpcClient{//RPC服务地址映射表publicstatic$rpcConfig=array("RewardScoreService"=>"http://10.211.55.4/yar/server/RewardScoreService.class.php",);publicstaticfunctioninit($server){if(array_key_exists($server,self::$rpcConfig)){$uri=self::$rpcConfig[$server];返回新的Yar_Client($uri);}}}$RewardScoreService=RpcClient::init("RewardScoreService");var_dump($RewardScoreService->support(1,2));服务端代码类RewardScoreService{/***$uidlikes$feedId*@param$feedIdinterge*@param$uidinterge*@returnvoid*/publicfunctionsupport($uid,$feedId){return"uid=".$uid.",feedId=".$feedId;}}$yar_server=newYar_server(newRewardScoreService());$yar_server->handle();你背后的故事就是我面前的故事sdk改造的代码演示一定要看这里,rpc框架不再那么神秘了。当然这只是rpc的一小部分,简单的远程调用。毕竟php是世界上最好的语言。java上的远程调用也是如此。如果把java远程调用换成java的话会麻烦一点。java实现之后,会让你感觉比较本土化,所以java也是最强大的语言。由于java是静态编译的,所以没有类似php中__call方法的方法来实现远程调用。一般使用动态代理来实现importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;/***zhoumengkang于2015年5月12日创建。*//***点赞服务接口*/interfaceRewardScoreService{Stringsupport(intuid,intfeedId);}publicclassSupportService{publicstaticvoidmain(String[]args){add(1,2);}/***uid喜欢feedId*@paramuid*@paramfeedId*@return*/publicstaticStringadd(intuid,intfeedId){YarClientyarClient=newYarClient();RewardScoreServicerewardScoreService=(RewardScoreService)yarClient.proxy(RewardScoreService.class);返回rewardScoreService.support(uid,feedId);}}classYarClient{publicfinalObjectproxy(Classtype){YarClientInvocationHandlerhandler=newYarClientInvocationHandler();返回Proxy.newProxyInstance(type.getClassLoader(),新类s[]{类型},处理程序);}}finalclassYarClientInvocationHandlerimplementsInvocationHandler{@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("这里动态调用实现php的__call方法");System.out.println("方法:"+method.getName());for(inti=0;i