RPC(Remote Promote Call) 一种进程间通信方式。允许像调用本地服务一样调用远程服务。

RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式(TCP或者UDP)、序列化方式(XML/JSON/二进制)和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。

                RPC框架原理图

简单的RPC代码实现

package Server;

public interface EchoService {
String echo(String ping); } package Server; public class EchoServiceImpl implements EchoService{ @Override
public String echo(String ping) {
// TODO Auto-generated method stub
return ping !=null?ping+"--> I am ok.":"I am bad.";
} } package Exporter; import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors; /**
* RPC服务端发布者
* 作为服务端,监听客户端的TCP连接,接收到新的客户端连接之后,将其封装成Task,由线程池执行
* 将客户端发送的码流反序列化成对象,反射调用服务实现者,获取执行结果
* 将执行结果对象发序列化,通过Socket发送给客户端
* 远程调用完成之后,释放Socket等连接资源,防止句柄泄露
* @author Administrator
*
*/
public class RpcExporter {
//创建一个可重用固定线程数的线程池
//Runtime.getRuntime().availableProcessors()返回虚拟机可用的处理器数量
static Executor executor=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public static void exporter(String hostname,int port) throws IOException {
//创建一个监听特定端口的Serversocket,负责接收客户连接请求
ServerSocket server = new ServerSocket();
//绑定主机名端口号
server.bind(new InetSocketAddress(hostname,port));
try{
while(true)
{
executor.execute(new ExporterTask(server.accept()));
}
}finally
{
server.close();
}
} private static class ExporterTask implements Runnable{ Socket client=null;
public ExporterTask(Socket client){
this.client=client;
}
@Override
public void run() {
// TODO Auto-generated method stub
ObjectInputStream input=null;
ObjectOutputStream output=null;
try{
//获取输入流
input=new ObjectInputStream(client.getInputStream());
//获取调用的接口名
String interfaceName = input.readUTF();
//加载接口
Class<?> service = Class.forName(interfaceName);
//获取调用的方法名
String methodName = input.readUTF();
//获取方法返回类型
Class<?>[] ParameterTypes = (Class<?>[]) input.readObject();
//获取参数
Object[] arguments = (Object[]) input.readObject();
//通过反射获取方法
Method method = service.getMethod(methodName, ParameterTypes);
//通过反射调用方法
Object result = method.invoke(service.newInstance(), arguments);
output = new ObjectOutputStream(client.getOutputStream());
output.writeObject(result);
}catch(Exception e){
e.printStackTrace();
}
finally{
if(output != null)
try{
output.close();
}catch ( IOException e){
e.printStackTrace();
} if(input !=null)
try{
input.close();
}catch(IOException e){
e.printStackTrace();
} if(client != null)
try{
client.close();
}catch (IOException e){
e.printStackTrace();
}
} } }
} package Client; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
*本地服务代理
*将本地的接口调用转换成JDK的动态代理,在动态代理中实现接口的远程调用
*创建Socket客户端,根据指定地址连接远程服务提供者
*将远程服务调用所需要的接口类,方法名,参数列表等编码参数发送给服务提供者
*同步阻塞等待服务端返回应答,获取应答之后返回
* @author Administrator
*
* @param <S>
*/
public class RpcImporter<S> {
@SuppressWarnings("unchecked")
public S importer(final Class<?> serviceClass,final InetSocketAddress addr)
{
return (S) Proxy.newProxyInstance(serviceClass.getClassLoader(), new Class<?>[] {serviceClass.getInterfaces()[0]}, new InvocationHandler() { @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Socket socket =null;
ObjectOutputStream output = null;
ObjectInputStream input = null;
try{
socket = new Socket();
socket.connect(addr);
//将远程服务调用所需要的接口类,方法名,参数列表等编码参数发送给服务提供者
output = new ObjectOutputStream(socket.getOutputStream());
output.writeUTF(serviceClass.getName());
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(args);
//同步阻塞等待服务端返回应答,获取应答之后返回
input= new ObjectInputStream(socket.getInputStream()); return input.readObject();
}
finally{
if(socket != null)
socket.close(); if(output != null)
output.close();
if(input != null)
input.close();
}
}
});
}
} package test; import java.net.InetSocketAddress; import Client.RpcImporter;
import Exporter.RpcExporter;
import Server.EchoService;
import Server.EchoServiceImpl; public class run { public static void main(String[] args) {
// TODO Auto-generated method stub //创建异步发布服务端的线程并启动,用于接受PRC客户端的请求,根据请求参数调用服务实现类,返回结果给客户端
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
try{
RpcExporter.exporter("localhost", 8088);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
//创建客户端服务代理类,构造RPC求情参数,发起RPC调用
RpcImporter<EchoService> importer=new RpcImporter<EchoService>();
EchoService echo = importer.importer(EchoServiceImpl.class, new InetSocketAddress("localhost",8088));
System.out.println(echo.echo("Are u ok?"));
} }

RPC框架实现的几个核心技术点

(1)远程提供者需要以某种形式提供服务调用相关的信息,包括但不限于服务接口定义、数据结构、或者中间态的服务定义文件。例如Facebook的 Thrift的IDL文件,Web service的WSDL文件;服务的调用者需要通过一定的图景获取远程服务调用相关的信息。

(2)远程代理对象:服务调用者用的服务实际是远程服务的本地代理。说白了就是通过动态代理来实现。

(3)通信:RPC框架与具体的协议无关。

(4)序列化:毕竟是远程通信,需要将对象转化成二进制流进行传输。不同的RPC框架应用的场景不同,在序列化上也会采取不同的技术

RPC面临的挑战

在大规模服务化之前,应用可能只是通过RPC框架,简单的暴露和引用远程服务,通过配置URL地址进行远程服务调用,路由则通过F5负载均衡器等进行简单的负载均衡。

当服务越来越多的时候,服务的URL配置管理变得更加困难。单纯的使用RPC就有点吃不消。所以在大规模分布式集群中,RPC只是作为集群的一个方法调用手段。例如在Hadoop的进程间交互都是通过RPC来进行的,比如Namenode与Datanode直接,Jobtracker与Tasktracker之间等。

RPC与Web Servie

讲道理,我觉得RPC与Webservice很像.可以说Web Service是在RPC发展的基础之上。web service是运行在web上的一个服务

RPC使用C/S方式,发送请求到服务器,等待服务器返回结果。

Web Service提供的服务是基于web容器的,底层使用http协议,类似一个远程的服务提供者,比如天气预报服务,对各地客户端提供天气预报,是一种请求应答的机制,是跨系统跨平台的。就是通过一个servlet,提供服务出去。

RPC与JMS

在RPC中,当一个请求到达RPC服务器时,这个请求就包含了一个参数集和一个文本值,通常形成“classname.methodname”的形式。这就向RPC服务器表明,被请求的方法在为“classname”的类中,名叫“methodname”。然后RPC服务器就去搜索与之相匹配的类和方法,并把它作为那种方法参数类型的输入。这里的参数类型是与RPC请求中的类型是匹配的。一旦匹配成功,这个方法就被调用了,其结果被编码后返回客户方。

JMS 一般只是一个点发出一个Message到Message Server,发出之后一般不会关心谁用了这个message。JMS可以做到异步调用完全隔离了客户端和服务提供者,能够抵御流量洪峰;JMS获得消息可以进行延迟处理,而RPC一般是进行实时调用。

相比较其他的通信而言,RPC的侧重点在于方法。并且是C/S架构方式

                    服务化架构的演进图

MVC架构:当业务规模很小时,将所有功能都不熟在同一个进程中,通过双机或者负载均衡器实现负债分流;此时,分离前后台逻辑的MVC架构是关键。

PRC架构:当垂直应用越来越多,应用之间交互不可避免,将核心和公共业务抽取出来,作为独立的服务,实现前后台逻辑分离。此时,用于提高业务复用及拆分的RPC框架是关键。

SOA架构:随着业务发展,服务数量越来越多,服务生命周期管控和运行态的治理成为瓶颈,此时用于提升服务质量的SOA服务治理是关键。

微服务架构:通过服务的原子化拆分,以及微服务的独立打包、部署和升级,小团队的交付周期将缩短,运维成本也将大幅度下降。

RPC架构简单理解的更多相关文章

  1. B/S和C/S架构简单理解

    B/S和C/S架构简单理解 B/S结构.C/S结构 B(browser浏览器)-S(server服务器),说简单点就是通过浏览器来请求服务器,实现数据交互.那自然了,C(client客户端软件)-S( ...

  2. [svc]简单理解什么是rpc调用?跟restapi有何区别?

    什么是rpc调用 restapi调用方式是对数据的crud. 常见的我们写flash写个api,或者借助django drf写个标准的resetapi,一个url可以借助httpget post pu ...

  3. RPC架构-美团,京东面试题目

    RPC(Remote Procedure Call) RPC服务 从三个角度来介绍RPC服务:分别是RPC架构,同步异步调用以及流行的RPC框架. RPC架构 先说说RPC服务的基本架构吧.允许我可耻 ...

  4. 关于RabbitMQ的简单理解

    说明:想要理解RabbitMQ,需要先理解MQ是什么?能做什么?然后根据基础知识去理解RabbitMQ是什么.提供了什么功能. 一.MQ的简单理解 1. 什么是MQ? 消息队列(Message Que ...

  5. SQL SERVER 2005/2008 中关于架构的理解(一)

    SQL SERVER 2005/2008 中关于架构的理解(一) 在一次的实际工作中碰到以下情况,在 SQL SERVER 2008中,新建了一个新用户去访问几张由其他用户创建的表,但是无法进行查询, ...

  6. 关于ASP.NET或VS2005 搭建三层架构的理解

    最近想学习ASP.NET建网站,关于ASP.NET或VS2005 搭建三层架构的理解,网上摘录了一些资料,对于第(2)点的讲解让我理解印象深刻,如下: (1)为何使用N层架构? 因为每一层都可以在仅仅 ...

  7. REST RPC架构思想

    1.REST RPC是什么? REST RPC是一个改进版的RPC架构,它是为了解决传统的RPC和REST方案的一些不足之处而生的,它结合了REST API和RPC的优点,同时又克服了REST API ...

  8. 【转】Linux 概念架构的理解

    转:http://mp.weixin.qq.com/s?__biz=MzA3NDcyMTQyNQ==&mid=400583492&idx=1&sn=3b18c463dcc451 ...

  9. 【转】SQL SERVER 2005/2008 中关于架构的理解

    在一次的实际工作中碰到以下情况,在 SQL SERVER 2008中,新建了一个新用户去访问几张由其他用户创建的表,但是无法进行查询,提示“对象名'CustomEntry' 无效.”.当带上了架构名称 ...

随机推荐

  1. ASP.NET Core学习之三 NLog日志

    上一篇简单介绍了日志的使用方法,也仅仅是用来做下学习,更何况只能在console输出. NLog已是日志库的一员大佬,使用也简单方便,本文介绍的环境是居于.NET CORE 2.0 ,目前的版本也只有 ...

  2. SQL server Error Number

    描述 HY000 所有绑定列都是只读的. 必须是可升级的列,以使用 SQLSetPos 或 SQLBulkOperations 更改或插入行. HY000 已检测到一个旧 netlib (%s).请删 ...

  3. StringMVC @RequestMapping method属性

    @RequestMapping(value="/testMethod",method=RequestMethod.POST) public String testMethod(){ ...

  4. VMware虚拟机下为Ubuntu添加磁盘

    20G的磁盘还是不够用啊,正好复习下磁盘分区和逻辑卷. 关闭虚拟机,打开VMware,右键虚拟机点击设置,点下下方的添加,就可以添加磁盘了. 进入虚拟机,查看: root@ubuntu:/# fdis ...

  5. and,or

    where语句的and or 连接 $map['_logic'] = 'and'; $map['_logic'] = 'or';

  6. 一种基于http协议的敏感数据传输方案

    最近公司需要通过公网与其它平台完成接口对接,但是基于开发时间和其它因素的考虑,本次对接无法采用https协议实现.既然不能用https协议,那就退而求其次采用http协议吧! 那么问题来了!在对接的过 ...

  7. 配置不同环境下启用swagger,在生产环境关闭swagger

    前言 Swagger使用起来简单方便,几乎所有的API接口文档都采用swagger了.使用示例:http://www.cnblogs.com/woshimrf/p/swagger.html, 现在开发 ...

  8. 微信小程序<web-view>嵌入网页后,小程序如何和网页交互传值?

    最近开发一个项目由于小程序某些组件的限制,然后想到嵌入网页,但是遇到一个问题:网页端调取数据的时候需要 小程序传递多个参数值才能用,如何传值呢? 最初我想到是<web-view src=&quo ...

  9. unity3d ipv6支持

    unity游戏应用提交app stroe需要通过ipv6测试,但是unity本身我没找到可用的接口,所以使用ios插件来处理. 插件的IOSNativeNet.h和IOSNativeNet.m代码: ...

  10. 魔方 NewLife.Cube

    魔方 是一个基于 ASP.NET MVC 的 用户权限管理平台,可作为各种信息管理系统的基础框架. 演示:http://cube.newlifex.com 源码 演示账号:admin/admin 源码 ...