博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
rpc
阅读量:5017 次
发布时间:2019-06-12

本文共 7076 字,大约阅读时间需要 23 分钟。

RPC框架性能大比拼 :

百分点 harpc git:

RPC 简介

      RPC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的主程序,可以调用另一台机器上的程序,就像LPC(本地过程调用)

越底层,代码越复杂、灵活性越高、效率越高
越上层,抽象封装的越好、代码越简单、效率越差
     Socket和RPC的区别再次说明了这点。在传统的编程概念中,过程是由程序员在本地编译完成,并只能局限在本地运行的一段代码,也即其主程序和过程之间的运行关系是本地调用关系。因此这种结构在网络日益发展的今天已无法适应实际需求。传统过程调用模式无法充分利用网络上其他主机的资源(如CPU、Memory等),也无法提高代码在实体间的共享程度,使得主机资源大量浪费。
     通过RPC我们可以充分利用非共享内存的多处理器环境(例如通过局域网连接得多台工作站),这样可以简便地将你的应用分布在多台工作站上,应用程序就像运行在一个多处理器的计算机上一样。你可以方便的实现过程代码共享,提高系统资源的利用率,也可以将以大量数值处理的操作放在处理能力较强的系统上运行,从而减轻前端机的负担。
     RPC作为普遍的C/S开发方法,开发效率高效,可靠.但RPC方法的基本原则是:以模块调用的简单性忽略通讯的具体细节,以便程序员不用关心C/S之间的通讯协议,集中精力对付实现过程.这就决定了 RPC生成的通讯包不可能对每种应用都有最恰当的处理办法,与Socket方法相比,传输相同的有效数据,RPC占用更多的网络带宽.
RPC是在Socket的基础上实现的,它比socket需要更多的网络和系统资源.另外,在对程序优化时,程序员虽然可以直接修改由rpcgen产生的令人费解的源程序,但对于追求程序设计高效率的RPC而言,获得的简单性则被大大削弱.
RPC 这个概念术语在上世纪 80 年代由 Bruce Jay Nelson 提出。这里我们追溯下当初开发 RPC 的原动机是什么?在 Nelson 的论文 "Implementing Remote Procedure Calls" 中他提到了几点:
    1. 简单:RPC 概念的语义十分清晰和简单,这样建立分布式计算就更容易。
    2. 高效:过程调用看起来十分简单而且高效。
    3. 通用:在单机计算中过程往往是不同算法部分间最重要的通信机制。
通俗一点说,就是一般程序员对于本地的过程调用很熟悉,那么我们把 RPC 作成和本地调用完全类似,那么就更容易被接受,使用起来毫无障碍。Nelson 的论文发表于 30 年前,其观点今天看来确实高瞻远瞩,今天我们使用的 RPC 框架基本就是按这个目标来实现的

RPC 实现

1、 服务调用方(client)调用以本地调用方式调用服务;
2、 client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;在Java里就是序列化的过程
3、 client stub找到服务地址,并将消息通过网络发送到服务端;
4、 server stub收到消息后进行解码,在Java里就是反序列化的过程;
5、 server stub根据解码结果调用本地的服务;
6、 本地服务执行处理逻辑;
7、 本地服务将结果返回给server stub;
8、 server stub将返回结果打包成消息,序列化;
9、 server stub将打包后的消息通过网络并发送至消费方
10、 client stub接收到消息,并进行解码, 反序列化;
11、 服务调用方(client)得到最终结果

RPC框架的目标就是把2-10步封装起来,把调用、编码/解码的过程封装起来,让用户像调用本地服务一样的调用远程服务。要做到对客户端(调用方)透明化服务, RPC框架需要考虑解决如下问题:
1、 服务端提供的服务如何发布,客户端如何发现服务;
2、 如何对请求对象和返回结果进行序列化和反序列化;
3、 如何更高效进行网络通信。

rpc vs http

RPC是一种编程模式,把对服务器的调用抽象为过程调用,通常还伴随着框架代码自动生成等功能。使用RPC做网络服务开发时,通常只需要实现服务器端的一个处理函数,其余的客户端调用,序列化反序列化,方法派发(收到什么样的消息,调用服务器端的什么函数)等都由框架或者生成的代码来完成,较大地减轻了网络服务开发和调用的复杂性。

HTTP是一种应用层网络协议,RPC可以采用自定义协议,也可以通过HTTP协议来传输,thrift,grpc,xml-rpc,json-rpc都是通过HTTP传输的。HTTP既支持长连接,也支持短连接。

常用的rpc框架

Dubbo

阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。不过,略有遗憾的是,据说在淘宝内部,dubbo由于跟淘宝另一个类似的框架HSF(非开源)有竞争关系,导致dubbo团队已经解散(参见http://www.oschina.net/news/55059/druid-1-0-9 中的评论),反到是当当网的扩展版本仍在持续发展,墙内开花墙外香。其它的一些知名电商如当当、京东、国美维护了自己的分支或者在dubbo的基础开发,但是官方的库缺乏维护,相关的依赖类比如Spring,Netty还是很老的版本(Spring 3.2.16.RELEASE, netty 3.2.5.Final),倒是有些网友写了升级Spring和Netty的插件。

Motan

新浪微博开源的一个Java 框架。它诞生的比较晚,起于2013年,2016年5月开源。Motan 在微博平台中已经广泛应用,每天为数百个服务完成近千亿次的调用。

rpcx

Go语言生态圈的Dubbo, 比Dubbo更轻量,实现了Dubbo的许多特性,借助于Go语言优秀的并发特性和简洁语法,可以使用较少的代码实现分布式的RPC服务。

gRPC

Google开发的高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。本身它不是分布式的,所以要实现上面的框架的功能需要进一步的开发。

thrift

Apache的一个跨语言的高性能的服务框架,也得到了广泛的应用

性能比较:

吞吐率:rpcx > thrift > grpc > montan > dubbo

平均响应时间: rpcx > thrift > grpc > montan > dubbo

 

举个栗子

一个非常简单的非分布式demo

定义 server stub

public class RPCServer {    private ExecutorService threadPool;      private static final int DEFAULT_THREAD_NUM = 10;            public RPCServer(){          threadPool = Executors.newFixedThreadPool(DEFAULT_THREAD_NUM);      }      public void register(Object service, int port) {         try {                  System.out.println("server starts...");                  ServerSocket server = new ServerSocket(port);                  Socket socket = null;                  while((socket = server.accept()) != null){                      System.out.println("client connected...");                      threadPool.execute(new Processor(socket, service));                  }              } catch (IOException e) {                  e.printStackTrace();              }              }            class Processor implements Runnable{          Socket socket;          Object service;          public Processor(Socket socket, Object service){              this.socket = socket;              this.service = service;          }          public void process(){          }          @Override          public void run() {              try {                  ObjectInputStream in = new ObjectInputStream(socket.getInputStream());                  String methodName = in.readUTF();                  Class
[] parameterTypes = (Class
[]) in.readObject(); Object[] parameters = (Object[]) in.readObject(); Method method = service.getClass().getMethod(methodName, parameterTypes); try { Object result = method.invoke(service, parameters); ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); out.writeObject(result); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } } }}
View Code

定义 client stub

public class RPCClient {    @SuppressWarnings("unchecked")      public static 
T getClient(Class
clazz, final String ip, final int port){ return (T) Proxy.newProxyInstance(RPCClient.class.getClassLoader(), new Class
[]{clazz}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Socket socket = new Socket(ip, port); ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); out.writeUTF(method.getName()); out.writeObject(method.getParameterTypes()); out.writeObject(args); System.out.println(method.getName()+method.getParameterTypes()+args); ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); return in.readObject(); } }); } }
View Code

定义接口 (server)

public interface HelloService {    public String hello(String name);}
View Code

定义实现类(server)

public class HelloServiceImpl implements HelloService {    @Override    public String hello(String name) {        return "hello "+name;    }}
View Code

启动 rpc服务

public class ServerStart {    public static void main(String[] args) {        HelloService helloService = new HelloServiceImpl();        RPCServer server = new RPCServer();        server.register(helloService, 5001);    }}
View Code

调用rpc服务 (client)

public class Client {    public static void main(String args[]) {        HelloService helloService = RPCClient.getClient(HelloService.class, "127.0.0.1", 5001);        System.out.println(helloService.hello("young z"));    }}
View Code

 

转载于:https://www.cnblogs.com/amei0/p/8569741.html

你可能感兴趣的文章
平台程序微信平台开发应用的签名
查看>>
程序卡OK6410裸板更新程序_update
查看>>
类的定义、声明使用
查看>>
编译安装mysql-5.6.40
查看>>
年终总结
查看>>
初创互联网公司技术架构变迁之路
查看>>
【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)
查看>>
【网络流24题】No. 13 星际转移问题 (网络判定 最大流)
查看>>
[模板] 字符串hash
查看>>
SGU438_The Glorious Karlutka River =)
查看>>
Linux集群及LVS简介
查看>>
简单几何(直线与圆的交点) ZOJ Collision 3728
查看>>
Codeforces Round #327 (Div. 2)
查看>>
如何解决Provisional headers are shown问题(转)
查看>>
实现简单的接口自动化测试平台
查看>>
EXCEL工作表合并
查看>>
ODAC(V9.5.15) 学习笔记(三)TOraSession(2)
查看>>
SQL中的replace函数
查看>>
java中的类型安全问题-Type safety: Unchecked cast from Object to ...
查看>>
如何解决最后一个尾注引用显示与致谢混为一谈的问题-下
查看>>