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. Swift3中数组创建方法

    转载自:http://blog.csdn.net/bwf_erg/article/details/70858865 数组是由一组类型相同的元素构成的有序数据集合.数组中的集合元素是有 序的,而且可以重 ...

  2. grpc介绍

    grpc入门(一) 一.什么是grpc grpc是谷歌开源的一款高性能的rpc框架 (https://grpc.io),可以使用protocol buffers作为IDL(Interface Defi ...

  3. HTML、CSS、JS 复习——序

    HTML在MVC中担任着M的角色.由HTML组成的节点称之为HTML DOM.要想成为一流的大神,就必须能分分钟建立起一个强大的HTML DOM.而要做到这点,就必须了解甚至精通HTML. CSS在M ...

  4. Java多线程窥探

    1.程序,进程,线程 标准定义:

  5. Mysql:执行source sql脚本时,出现:error 2

    Centos下部署mysql: 1.yum -y install mysql*; 2.service mysqld start; 3.chkconfig mysqld on; 4.设置用户名和密码:m ...

  6. Error: Your project contains C++ files but it is not using a supported native build system

    我在编写有关JNI的代码的时候回报这个错误,我在网上搜了相关的资料后,找到了一篇文章解决了这个问题,点击这里查看这篇文章,我在照着这篇文章尝试的时候,总有一些错误,现在我把自己详细的解决流程贴出来,供 ...

  7. Global exception handling in asp.net core webapi

    在.NET Core中MVC和WebAPI已经组合在一起,都继承了Controller,但是在处理错误时,就很不一样,MVC返回错误页面给浏览器,WebAPI返回Json或XML,而不是HTML.Us ...

  8. Running Solr in Docker

    Docker现在越来越火,所有的应用程序都想Docker一下,但是并没有听说在Docker上运行Solr.在没有Docker之前要想使用Solr需要在宿主机安装JDK,安装Tomcat,下载Solr程 ...

  9. 【.Net边角料系列】1-单例模式(我真不是你想的那样)

    什么事边角料? 边角料就是你编程的时候,很少能够用上,或者说你压根就不知道得东西,我就称这些东西为边角料.这个叫.net边角料可能有点大,其实这个系列是纯粹的C#边角料系列. 为什么写.net边角料呢 ...

  10. Redis随笔(二)redis desktop manager 安装并且连接redis服务器

    1.首先在win10下安装redis desktop manager 2.查看虚拟机防火墙状态,启动状态,则关闭掉 查看防火墙状态: systemctl status firewalld.servic ...