在了解了前面咱们关于服务治理出现的必要性以后。咱们知道服务治理是创建在众多“服务”基础之上的,那么,第一步,打通这些服务是基础,也就是咱们常说的 RPC 远程调用。要像调用本地方法同样调用远程服务器上的方法。php
如今简单粗暴口语化的方式来介绍一个需求:java
A 服务器上部署的项目中,有一个
UserService
里面有一个getUserInfo
的方法。
B 服务器上想"直接"调用该方法,怎么办?git
咱们以 PHP 为例来进行分析。
咱们但愿在 B 服务器上实现相似于 A 服务器上直接调用方式github
$userService = new UserService(); $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
。json
咱们只须要在原来的基础上稍做修改便可,下面的代码仅作简单的演示segmentfault
该服务部署在localhost:8081
api
class UserService { public static function getUserInfo($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); echo json_encode($res);
class Client { private $url; private $service; private $rpcConfig = [ "UserService" => "http://127.0.0.1:8081", ]; /** * Client constructor. * @param $service */ public function __construct($service) { if (array_key_exists($service, $this->rpcConfig)) { $this->url = $this->rpcConfig[$service]; $this->service = $service; } } public function __call($action, $arguments) { $content = json_encode($arguments); $options['http'] = [ 'timeout' => 5, 'method' => 'POST', 'header' => 'Content-type:application/x-www-form-urlencoded', 'content' => $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); return json_decode($res, true); } } $userService = new Client('UserService'); var_export($userService->getUserInfo(103));
这样是否是就很是方便的在客户端实现了像在本地同样调用远程的方法呢?这也是鸟哥 @Laruence yar 的操做原理。下面对比下 Yar 的 demo:服务器
yar https://github.com/laruence/yar
yar 的 java 客户端 https://github.com/zhoumengka...app
客户端代码,假设该服务设在局域网10.211.55.4上
class RpcClient { // RPC 服务地址映射表 public static $rpcConfig = array( "RewardScoreService" => "http://10.211.55.4/yar/server/RewardScoreService.class.php", ); public static function init($server){ if (array_key_exists($server, self::$rpcConfig)) { $uri = self::$rpcConfig[$server]; return new Yar_Client($uri); } } } $RewardScoreService = RpcClient::init("RewardScoreService"); var_dump($RewardScoreService->support(1, 2));
服务器端代码
class RewardScoreService { /** * $uid 给 $feedId 点赞 * @param $feedId interge * @param $uid interge * @return void */ public function support($uid,$feedId){ return "uid = ".$uid.", feedId = ".$feedId; } } $yar_server = new Yar_server(new RewardScoreService()); $yar_server->handle();
yar 背后的故事就是我前面那段 sdk 改造的代码演示。想必看到这里,rpc 框架再也不那么神秘了吧。
固然这只是实现了 rpc 的一小部分,简单的远程调用。毕竟 php 是世界上最好的语言。
java 上面执行远程调用也相似。
若是换成 java 可稍微麻烦点,java 实现起来以后会让你以为更加的本地化,因此 java 也是最强大的语言。
因为 java 是静态编译的,不存在相似于 php 里的__call方法的方式来实现远程调用,通常经过动态代理
来实现
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Created by zhoumengkang on 5/12/15. */ /** * 点赞的积分服务接口 */ interface RewardScoreService{ String support(int uid,int feedId); } public class SupportService { public static void main(String[] args) { add(1,2); } /** * uid 给 feedId 点赞 * @param uid * @param feedId * @return */ public static String add(int uid, int feedId){ YarClient yarClient = new YarClient(); RewardScoreService rewardScoreService = (RewardScoreService) yarClient.proxy(RewardScoreService.class); return rewardScoreService.support(uid, feedId); } } class YarClient { public final Object proxy(Class type) { YarClientInvocationHandler handler = new YarClientInvocationHandler(); return Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, handler); } } final class YarClientInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("这里的动态调用实现了 php 的 __call 方法"); System.out.println("method : " + method.getName()); for (int i = 0; i < args.length; i++) { System.out.println("args["+ i +"] : " + args[i]); } return null; } }
看完本篇,是否是顿时以为 rpc 框架再也不那么神秘,有一点点感受了呢?
老铁周末的直播:揭开她的神秘面纱 - 零基础构建本身的服务治理框架 赶快上车
https://segmentfault.com/l/15...