RPC的解释以及RPC和Restful、RPC和RMI的区别

如何科学的解释RPC

提及RPC,就不能不提到分布式,这个促使RPC诞生的领域。html

假设你有一个计算器接口,Calculator,以及它的实现类CalculatorImpl,那么在系统仍是单体应用时,你要调用Calculator的add方法来执行一个加运算,直接new一个CalculatorImpl,而后调用add方法就好了,这其实就是很是普通的本地函数调用,由于在同一个地址空间,或者说在同一块内存,因此经过方法栈和参数栈就能够实现。java

 
 

 

如今,基于高性能和高可靠等因素的考虑,你决定将系统改造为分布式应用,将不少能够共享的功能都单独拎出来,好比上面说到的计算器,你单独把它放到一个服务里头,让别的服务去调用它。apache

 
 

这下问题来了,服务A里头并无CalculatorImpl这个类,那它要怎样调用服务B的CalculatorImpl的add方法呢?编程

有同窗会说,能够模仿B/S架构的调用方式呀,在B服务暴露一个Restful接口,而后A服务经过调用这个Restful接口来间接调用CalculatorImpl的add方法。缓存

很好,这已经很接近RPC了,不过若是是这样,那每次调用时,是否是都须要写一串发起http请求的代码呢?好比httpClient.sendRequest...之类的,能不能像本地调用同样,去发起远程调用,让使用者感知不到远程调用的过程呢,像这样:网络

@Reference private Calculator calculator; ... calculator.add(1,2); ... 

这时候,有同窗就会说,用代理模式呀!并且最好是结合Spring IoC一块儿使用,经过Spring注入calculator对象,注入时,若是扫描到对象加了@Reference注解,那么就给它生成一个代理对象,将这个代理对象放进容器中。而这个代理对象的内部,就是经过httpClient来实现RPC远程过程调用的。架构

可能上面这段描述比较抽象,不过这就是不少RPC框架要解决的问题和解决的思路,好比阿里的Dubbo。负载均衡

总结一下,RPC要解决的两个问题:框架

  1. 解决分布式系统中,服务之间的调用问题。
  2. 远程调用时,要可以像本地调用同样方便,让调用者感知不到远程调用的逻辑。

如何实现一个RPC

实际状况下,RPC不多用到http协议来进行数据传输,毕竟我只是想传输一下数据而已,何须动用到一个文本传输的应用层协议呢,我为何不直接使用二进制传输?好比直接用Java的Socket协议进行传输?异步

无论你用何种协议进行数据传输,一个完整的RPC过程,均可以用下面这张图来描述:

 
 

以左边的Client端为例,Application就是rpc的调用方,Client Stub就是咱们上面说到的代理对象,也就是那个看起来像是Calculator的实现类,其实内部是经过rpc方式来进行远程调用的代理对象,至于Client Run-time Library,则是实现远程调用的工具包,好比jdk的Socket,最后经过底层网络实现实现数据的传输。

这个过程当中最重要的就是序列化和反序列化了,由于数据传输的数据包必须是二进制的,你直接丢一个Java对象过去,人家可不认识,你必须把Java对象序列化为二进制格式,传给Server端,Server端接收到以后,再反序列化为Java对象。

下一次我也将经过代码,给你们演示一下,如何实现一个简单的RPC。

RPC vs Restful

其实这二者并非一个维度的概念,总得来讲RPC涉及的维度更广。

若是硬要比较,那么能够从RPC风格的url和Restful风格的url上进行比较。

好比你提供一个查询订单的接口,用RPC风格,你可能会这样写:

/queryOrder?orderId=123

用Restful风格呢?

Get  
/order?orderId=123

RPC是面向过程,Restful是面向资源,而且使用了Http动词。从这个维度上看,Restful风格的url在表述的精简性、可读性上都要更好。

RPC vs RMI

严格来讲这二者也不是一个维度的。

RMI是Java提供的一种访问远程对象的协议,是已经实现好了的,能够直接用了。

而RPC呢?人家只是一种编程模型,并无规定你具体要怎样实现,你甚至均可以在你的RPC框架里面使用RMI来实现数据的传输,好比Dubbo:Dubbo - rmi协议

RPC没那么简单

要实现一个RPC不算难,难的是实现一个高性能高可靠的RPC框架。

好比,既然是分布式了,那么一个服务可能有多个实例,你在调用时,要如何获取这些实例的地址呢?

这时候就须要一个服务注册中心,好比在Dubbo里头,就可使用Zookeeper做为注册中心,在调用时,从Zookeeper获取服务的实例列表,再从中选择一个进行调用。

那么选哪一个调用好呢?这时候就须要负载均衡了,因而你又得考虑如何实现复杂均衡,好比Dubbo就提供了好几种负载均衡策略。

这还没完,总不能每次调用时都去注册中心查询实例列表吧,这样效率多低呀,因而又有了缓存,有了缓存,就要考虑缓存的更新问题,blablabla......

你觉得就这样结束了,没呢,还有这些:

  • 客户端总不能每次调用完都干等着服务端返回数据吧,因而就要支持异步调用;
  • 服务端的接口修改了,老的接口还有人在用,怎么办?总不能让他们都改了吧?这就须要版本控制了;
  • 服务端总不能每次接到请求都立刻启动一个线程去处理吧?因而就须要线程池;
  • 服务端关闭时,还没处理完的请求怎么办?是直接结束呢,仍是等所有请求处理完再关闭呢?
  • ......

如此种种,都是一个优秀的RPC框架须要考虑的问题。

固然,接下来咱们仍是先实现一个简单的RPC,再在上面一步步优化!

做者:柳树之
连接:https://www.jianshu.com/p/2accc2840a1b来源:简书著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。

相关文章
相关标签/搜索