【分布式】RPC初探
事先声明:本文代码参考自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初探的更多相关文章
- 基于netty轻量的高性能分布式RPC服务框架forest<下篇>
基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开 ...
- 基于netty轻量的高性能分布式RPC服务框架forest<上篇>
工作几年,用过不不少RPC框架,也算是读过一些RPC源码.之前也撸过几次RPC框架,但是不断的被自己否定,最近终于又撸了一个,希望能够不断迭代出自己喜欢的样子. 顺便也记录一下撸RPC的过程,一来作为 ...
- 一个轻量级分布式RPC框架--NettyRpc
1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个轻量级的分布式RPC ...
- 轻量级分布式 RPC 框架
@import url(/css/cuteeditor.css); 源码地址:http://git.oschina.net/huangyong/rpc RPC,即 Remote Procedure C ...
- 基于开源Dubbo分布式RPC服务框架的部署整合
一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目 ...
- 【转】轻量级分布式 RPC 框架
第一步:编写服务接口 第二步:编写服务接口的实现类 第三步:配置服务端 第四步:启动服务器并发布服务 第五步:实现服务注册 第六步:实现 RPC 服务器 第七步:配置客户端 第八步:实现服务发现 第九 ...
- 【原】Storm分布式RPC
5. Storm高级篇 序列化 分布式RPC High level overview LinearDRPCTopologyBuilder Local mode DRPC Remote mode DRP ...
- 轻量级分布式RPC框架
随笔- 139 文章- 0 评论- 387 一个轻量级分布式RPC框架--NettyRpc 1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 ...
- RSF 分布式 RPC 服务框架的分层设计
RSF 是个什么东西? 一个高可用.高性能.轻量级的分布式服务框架.支持容灾.负载均衡.集群.一个典型的应用场景是,将同一个服务部署在多个Server上提供 request.response 消息通知 ...
- 一个轻量级分布式 RPC 框架 — NettyRpc
原文出处: 阿凡卢 1.背景 最近在搜索Netty和Zookeeper方面的文章时,看到了这篇文章<轻量级分布式 RPC 框架>,作者用Zookeeper.Netty和Spring写了一个 ...
随机推荐
- U盘启动笔记本无法安装Win7问题和解决
用“大白菜”工具制作启动U盘,从U盘启动后进入Win PE环境安装Win7,提示“安装win7系统安装程序无法创建新的系统分区,也无法定位现有系统分区”.经以下各种努力后仍无法正常安装: 在BIOS里 ...
- IUnknown—COM和MFC
http://www.vckbase.com/index.php/wv/60 问题: 我用MFC编写COM程序有一段时间了,知道如何使用宏和嵌套类,以及如何在嵌套类中处理IUnknown接口,但对IU ...
- 转:MPlayer源代码分析
一.Mplayer支持的格式 MPlayer是一个LINUX下的视频播放器,它支持相当多的媒体格式,无论在音频播放还是在视频播放方面,可以说它支持的格式是相当全面的. 视频格式支持:MPEG.AVI. ...
- Qt 调试时的错误——Debug Assertion Failed!
在VS2008中写qt程序时调试出现此问题,但在release模式下就不存在,在网上搜罗了一圈,是指针的问题. 问题是这样的: 需要打开两个文件,文件中数据类型是float,我使用QVector进行保 ...
- IOS越狱开发之——进程通讯
Mac OS下的IPC方式种类很多,大约有下面几种. 1. Mach API 2. CFMessagePort 3. Distributed Objects (DO) 4. Apple events ...
- OpenCV仿射变换+投射变换+单应性矩阵
本来想用单应性求解小规模运动的物体的位移,但是后来发现即使是很微小的位移也会带来超级大的误差甚至错误求解,看起来这个方法各种行不通,还是要匹配知道深度了以后才能从三维仿射变换来入手了,纠结~ esti ...
- iOS客户端的在线安装和更新——针对ADHoc证书
这篇文章纯给自己留个备份,所以对AdHoc证书内部分发和对iOS客户端开发不了解的请直接无视. 一般在iOS游戏或应用开发过程中,正式发布到App Store之前,都需要内部的测试,客户端的安装是个不 ...
- 在Oracle Linux Server release 6.4下配置ocfs2文件系统
① 安装ocfs-tools-1.8 如果是使用RedHat Enterprise Linux 6.4,也可以安装ocfs-tools-1.8的,只是要插入Oracle Linux Server re ...
- ADT公司G729 方案指标
ADT公司G729 方案指标 G.729 Voice Compression Algorithm and its many annexes G.729 is used in wireless voic ...
- 在线制作h5——上帝的礼物
在线制作h5 网址:http://www.godgiftgame.com 网站名称:上帝的礼物 推荐指数:5颗星 功能概要 可以设置背景.元素图片.元素文字.元素图形.声音.加载.链接.分享,生成h5 ...