事先声明:本文代码参考自Dubbo作者的博客

RPC(Remote Procedure Call)远程过程调用,是分布式系统当中必不可少的一个玩意。比如说在单机系统当中,我想调用某个方法,直接调就可以了对吧,但是当环境变成多机分布式系统时,A机器上想调用B机器上的某个方法时,就需要用到RPC了。RPC的原理在知乎这个问答上有很清楚的解释。

简单点来说,就是客户端利用了socket把希望调用的方法的信息(方法名、方法需要的参数等)传给服务器端,服务器端把这些信息反序列化之后利用反射去调用指定的方法,并把返回值再通过socket返回给客户端。下面是代码示例,关键部分我写了自己理解的注释。

代码主要用到了socket通信和JDK的动态代理,这两部分我在之前的博客中也都有涉及。

RPCServer.java

public class RPCServer {
private static final int PORT = 8000;
/**
* 暴露服务
*
* @param service 服务的对象实例
* */
public static void open(final Object service) throws Exception {
if (service == null) {
throw new IllegalArgumentException();
}
System.out.println("Service is opening for " + service.getClass().getName() + " at port: " + PORT);
//开启ServerSocket监听8000端口
final ServerSocket server = new ServerSocket(PORT);
for (;;) {
try {
//接收到一个客户端请求
final Socket client = server.accept();
//开一个线程处理
new Thread(new Runnable() {
@Override
public void run() {
try {
ObjectInputStream input = new ObjectInputStream(client.getInputStream());
try {
String methodName = input.readUTF();
System.out.println(">>>>methodName: " + methodName);
Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
System.out.println(">>>>arguments: " + arguments.toString());
ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
try {
//利用反射获取到方法对象
Method method = service.getClass().getMethod(methodName, parameterTypes);
//调用方法并获取返回值
Object result = method.invoke(service, arguments);
//把返回值写入socket,返回给客户端
out.writeObject(result);
// out.flush();
} catch (Throwable t) {
out.writeObject(t);
} finally {
out.close();
}
} finally {
input.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* 指定在远程主机上的服务
*
* @param <T> 接口泛型
* @param interfaceClass 接口
* @param host 远程主机IP
* */ @SuppressWarnings("unchecked")
public static <T> T refer(final Class<T> interfaceClass, final String host) {
if (interfaceClass == null) {
throw new IllegalArgumentException("invalid interface");
}
if (host == null || "".equals(host)) {
throw new IllegalArgumentException("invalid host");
}
System.out.println("Get remote service " + interfaceClass.getName() + " from server " + host + ":" + PORT);
//动态代理返回对象实例,并且利用泛型转成服务类型
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = new Socket(host, PORT);
try {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
try {
//发送方法名
out.writeUTF(method.getName());
//发生方法参数列表
out.writeObject(method.getParameterTypes());
//发生方法需要的参数
out.writeObject(args);
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
try {
//获取返回值
Object result = input.readObject();
if (result instanceof Throwable) {
throw (Throwable) result;
}
return result;
}finally {
input.close();
}
}finally {
out.close();
}
} finally {
socket.close();
}
}
});
}
}

接口 HelloService.java

public interface HelloService {
public String show(String name);
}

接口实现 HelloServiceImpl.java

public class HelloServiceImpl implements HelloService {
@Override
public String show(String name) {
System.out.println(name);
return "name: " + name;
}
}

测试:

服务端测试代码 ServerTest.java

public class ServerTest {
public static void main(String[] args) throws Exception {
HelloService helloService = new HelloServiceImpl();
//开启RPC服务,并且绑定一个对象实例,指定服务器上的服务类型
RPCServer.open(helloService);
}
}

客户端测试代码 ClientTest.java

public class ClientTest {
public static void main(String[] args) {
try {
//调用指定IP的远程主机上的指定服务
HelloService service = RPCServer.refer(HelloService.class, "127.0.0.1");
System.out.println(service.show("hello"));
}catch (Exception e) {
e.printStackTrace();
}
}
}

结果如下:

服务端:

客户端:

思考

关于这段示例代码,有哪些改进的地方呢?首先我想到的是把TCP通信模型改成NIO通信,不要用BIO这种低并发的模型;其次是传输的信息可以用其他方式进行压缩或者叫序列化,减少传输的大小从而降低服务器压力和提高传输速度;还有就是这段代码使用的动态代理是JDK自带的方法,有个很大的缺点是必须要接口,之前的文章也提到了,可以采用CGlib来改善一下。目前能想到的就这三点了,找时间我再来完善一下。

同时也可以去看看Dubbo源码。

【分布式】RPC初探的更多相关文章

  1. 基于netty轻量的高性能分布式RPC服务框架forest<下篇>

    基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开 ...

  2. 基于netty轻量的高性能分布式RPC服务框架forest<上篇>

    工作几年,用过不不少RPC框架,也算是读过一些RPC源码.之前也撸过几次RPC框架,但是不断的被自己否定,最近终于又撸了一个,希望能够不断迭代出自己喜欢的样子. 顺便也记录一下撸RPC的过程,一来作为 ...

  3. 一个轻量级分布式RPC框架--NettyRpc

    1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个轻量级的分布式RPC ...

  4. 轻量级分布式 RPC 框架

    @import url(/css/cuteeditor.css); 源码地址:http://git.oschina.net/huangyong/rpc RPC,即 Remote Procedure C ...

  5. 基于开源Dubbo分布式RPC服务框架的部署整合

    一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目 ...

  6. 【转】轻量级分布式 RPC 框架

    第一步:编写服务接口 第二步:编写服务接口的实现类 第三步:配置服务端 第四步:启动服务器并发布服务 第五步:实现服务注册 第六步:实现 RPC 服务器 第七步:配置客户端 第八步:实现服务发现 第九 ...

  7. 【原】Storm分布式RPC

    5. Storm高级篇 序列化 分布式RPC High level overview LinearDRPCTopologyBuilder Local mode DRPC Remote mode DRP ...

  8. 轻量级分布式RPC框架

    随笔- 139  文章- 0  评论- 387  一个轻量级分布式RPC框架--NettyRpc   1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 ...

  9. RSF 分布式 RPC 服务框架的分层设计

    RSF 是个什么东西? 一个高可用.高性能.轻量级的分布式服务框架.支持容灾.负载均衡.集群.一个典型的应用场景是,将同一个服务部署在多个Server上提供 request.response 消息通知 ...

  10. 一个轻量级分布式 RPC 框架 — NettyRpc

    原文出处: 阿凡卢 1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个 ...

随机推荐

  1. 苹果App部署HTTPS进行在线下载安装

    苹果App的ipa下载需要有几个前提,可参考:Android和IOS的本地App如何安装(apk&ipa) 本文主要介绍如何部署https提供ipa的下载,步骤如下: 1. 搭建一个HTTPS ...

  2. Lucene 4.X 倒排索引原理与实现: (3) Term Dictionary和Index文件 (FST详细解析)

    我们来看最复杂的部分,就是Term Dictionary和Term Index文件,Term Dictionary文件的后缀名为tim,Term Index文件的后缀名是tip,格式如图所示. Ter ...

  3. A Brief History of Scaling LinkedIn

    原文地址 LinkedIn started in 2003 with the goal of connecting to your network for better job opportuniti ...

  4. 一个类有两个方法,其中一个是同步的,另一个是非同步的; 现在又两个线程A和B,请问:当线程A访问此类的同步方法时,线程B是否能访问此类的非同步方法?

    一个类有两个方法,其中一个是同步的,另一个是非同步的:现在又两个线程A和B,请问:当线程A访问此类的同步方法时,线程B是否能访问此类的非同步方法? 答案:可以 验证 package com.my.te ...

  5. HDU 4686 Arc of Dream (矩阵快速幂)

    Arc of Dream Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Tota ...

  6. Mac OSX系统下SVN客户端SCPlugin问题

    装上SCPlugin后,Checkout老是出现这种错误: Server certificate verification failed: certificate issued for a diffe ...

  7. ch2 创建和销毁对象

    ch2 创建和销毁对象              

  8. Mac Jenkins 权限问题

    在官网下载dmg安装包,安装完毕即可在本机搭建jenkins的工作.但是jenkins不会用本地的用户去构建,任何创建的文件都是“jenkins”用户所有,这会造成很多权限问题,无法调用自己写的脚本, ...

  9. floor相关

    select floor(@f*0.22) -- 直接可显示结果 create table demo( id ,), id1 int ) select * from demo insert into ...

  10. win7搭建ios开发环境

    安装过程参考文章: http://jingyan.baidu.com/article/ff411625b9011212e48237b4.html http://www.loukit.com/threa ...