各种抄,理解还不够透彻,等着精简一下
从架构风格的抽象高度来看,常见的分布式应用架构风格有三种:
1、分布式对象(Distributed Objects,简称 DO)
– 架构实例有 CORBA/RMI/EJB/DCOM/.NET Remoting 等等
2、远程过程调用(Remote Procedure Call,简称 RPC)
– 架构实例有 SOAP/XML-RPC/Hessian/Flash AMF/DWR 等等
3、表现层状态转移(Representational State Transfer,简称 REST)
– 架构实例有 HTTP/WebDAV
DO 和 RPC 这两种架构风格在企业应用中非常普遍,而 REST 则是 Web 应用的架构风格,它们之间有非常大的差别。
现在互联网应用的量级越来越大,单台计算机的能力有限,需要借助可扩展的计算机集群来完成,分布式的应用可以借助RPC来完成机器之间的调用。
RPC(Remote Procedure Call)是远程过程调用的简称,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。
在OSI网络通信模型中,RPC跨越了传输层和应用层。
RPC使得开发包括网络分布式多程序在内的应用程序更加容易。在面向对象编程的程序中,RPC也可以用Remote method invocation(RMI)来展现。
主流远程框架 Thrift、谷歌的基于 ProtoBuf 的gRPC、Dubbo、Hessian、java RMI。
RPC,全称为Remote Procedure Call,即远程过程调用,是一种计算机通信协议。
比如现在有两台机器:A机器和B机器,并且分别部署了应用A和应用B。
假设此时位于A机器上的A应用想要调用位于B机器上的B应用提供的函数或是方法,
由于A应用和B应用不在一个内存空间里面,所以不能直接调用,此时就需要通过网络来表达调用的方式和传输调用的数据。
也即所谓的远程调用。
主要是在几个进程中(应用分布在不同的机器上),无法共用内存空间,
或者在一台机器内通过本地调用无法完成相关的需求(如不同系统之间的通信,或者不同组织之间的通信)
或者由于机器的横向扩展,需要在多台机器组成的集群上部署应用。
RPC的实现主要的两种类型:
最早的CORBA、Java RMI, WebService方式的RPC风格, Hessian, Thrift甚至Rest API。
RPC允许一台计算机调用另一台计算机上的程序得到结果,而代码中不需要做额外的编程,就像在本地调用一样。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。
在RPC框架中主要有三个角色:
RPC框架要做最基本的三件事:—Thrift框架即可完成
1 服务端如何确定客户端要调用的函数;
在远程调用中,客户端和服务端分别维护一个【ID->函数】的对应表, ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,附上这个ID,服务端通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
2 如何进行序列化和反序列化;
客户端和服务端交互时将参数或结果转化为字节流在网络中传输,那么数据转化为字节流的或者将字节流转换成能读取的固定格式时就需要进行序列化和反序列化,序列化和反序列化的速度也会影响远程调用的效率。
3 如何进行网络传输(选择何种网络协议)–高效地进行网络通信;
多数RPC框架选择TCP作为传输协议,也有部分选择HTTP。
服务端提供的服务如何暴露给客户端?
客户端如何发现这些暴露的服务?
业界使用的RPC通信框架以thrift居多,thrift框架把以上三件事都做了。
实现基础:
1、建立通信
首先要解决机器之间的通信问题,在客户端和服务器之间建立TCP连接,远程调用的相关数据都在连接中进行传输交换。
通常这个连接可以是按需连接(需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接。
2、服务寻址
解决寻址的问题:即A机器上的应用A要调用B机器上的应用B,那么此时对于A来说如何告知底层的RPC框架所要调用的服务具体在哪里呢?
通常情况下我们需要提供B机器(主机名或IP地址)以及特定的端口,然后指定调用的方法或者函数的名称以及入参出参等信息,这样才能完成服务的一个调用。比如基于Web服务协议栈的RPC,就需要提供一个endpoint URI,或者是从UDDI服务上进行查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
3、网络传输
(1)序列化
当A机器上的应用发起一个RPC调用时,调用方法和其入参等信息需要通过底层的网络协议如TCP传输到B机器,由于网络协议是基于二进制的,所有我们传输的参数数据都需要先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输。然后通过寻址操作和网络传输将序列化或者编组之后的二进制数据发送给B机器。
(2)反序列化
当B机器接收到A机器的应用发来的请求之后,又需要对接收到的参数等信息进行反序列化操作(序列化的逆操作),即将二进制信息恢复为内存中的表达方式,然后再找到对应的方法(寻址的一部分)进行本地调用(一般是通过生成代理Proxy去调用, 通常会有JDK动态代理、CGLIB动态代理、Javassist生成字节码技术等),之后得到调用的返回值。
4、服务调用
B机器进行本地调用(通过代理Proxy)之后得到了返回值,此时还需要再把返回值发送回A机器,同样也需要经过序列化操作,然后再经过网络传输将二进制数据发送回A机器,而当A机器接收到这些返回值之后,则再次进行反序列化操作,恢复为内存中的表达方式,最后再交给A机器上的应用进行相关处理(一般是业务逻辑处理操作)。
RPC架构组件:
1、客户端(Client):服务调用方(服务消费者)
2、客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端
3、服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理
4、服务端(Server):服务的真正提供者
调用过程:
1、服务消费者(client客户端)通过本地调用的方式调用服务
2、客户端存根(client stub)接收到调用请求后负责将方法、参数等信息序列化成能够进行网络传输的消息体
3、客户端存根(client stub)找到远程的服务地址,并且将消息通过网络发送给服务端
4、服务端存根(server stub)收到消息后进行解码(反序列化操作)
5、服务端存根(server stub)根据解码结果调用本地的服务进行相关处理
6、本地服务执行具体业务逻辑并将处理结果返回给服务端存根(server stub)
7、服务端存根(server stub)将返回结果重新打包成消息(序列化)并通过网络发送至消费方
8、客户端存根(client stub)接收到消息,并进行解码(反序列化)
9、服务消费方得到最终结果
因为很多程序采用了不同的编程语言(Java,C, C++ etc.)和不同的操作系统(Windows, CentOs, RHEL etc ,要保证数据能够正常通讯,并且不受语言和操作系统等限制,
就需要通讯标准,也就是IDL(Interface Description Language)接口定义语言。比如Apache的Thrift 和Google的 Protocol Buffers等。
服务提供者启动后主动向注册中心注册机器ip、port以及提供的服务列表;
服务消费者启动时向注册中心获取服务提供方地址列表,可实现软负载均衡和Failover;
生成 client stub和server stub需要用到 Java 动态代理技术
可以使用JDK原生的动态代理机制,可以使用一些开源字节码工具框架 如:CgLib、Javassist等。
为了能在网络上传输和接收 Java对象,我们需要对它进行 序列化和反序列化操作。
**序列化:**将Java对象转换成字节序列byte[]的过程,也就是编码的过程;
**反序列化:**将字节序列byte[]恢复成Java对象的过程,也就是解码的过程;
可以使用Java原生的序列化机制,但是效率非常低,推荐使用一些开源的、成熟的序列化技术,例如:protobuf、Thrift、hessian、Kryo、Msgpack
关于序列化工具性能比较可以参考:jvm-serializers
当前很多RPC框架都直接基于netty这一IO通信框架,比如阿里巴巴的HSF、dubbo,Hadoop Avro,推荐使用Netty 作为底层通信框架。
可选技术:Redis、Zookeeper、Consul、Etcd
一般使用ZooKeeper提供服务注册与发现功能,解决单点故障以及分布式部署的问题(注册中心)。
开源的优秀RPC框架:
补充:RPC和Socket区别:
首先:REST与RPC都是网络交互的协议规范。通常用于多个微服务之间的通信协议。
RPC风格曾是Web Service的主流,最初是基于XML-RPC协议(一个远程过程调用RPC的分布式计算协议),后来渐渐被简单对象访问协议(Simple Object Access Protocol, SOAP)取代;RPC风格的服务,不仅可以用HTTP,还可以用TCP或其他通信协议。但RPC风格的服务,受开发服务采用语言的束缚比较大,(如.NET框架中,开发web service的传统方式是使用WCF,基于WCF开发的服务即RPC风格的服务,使用该服务的客户端通常要用C#来实现,如果使用python或其他语言,很难实现可以直接与服务通信客户端);进入移动互联网时代后,RPC风格的服务很难在移动终端使用,而RESTful风格的服务,由于可以直接以json或xml为载体承载数据,以HTTP方法为统一接口完成数据操作,客户端的开发不依赖于服务实现的技术,移动终端也可以轻松使用服务,这也加剧了REST取代RPC成为web service的主导。
特点 | RPC | REST |
---|---|---|
通信协议 | 一般使用TCP | HTTP |
性能 | 高 | 低 |
灵活度 | 低 | 高 |
REST和RPC都常用于微服务架构中。
HTTP相对更规范,更标准,更通用,无论哪种语言都支持http协议。如果你是对外开放API,例如开放平台,外部的编程语言多种多样,你无法拒绝对每种语言的支持,现在开源中间件,基本最先支持的几个协议都包含RESTful。
REST调用及测试都很方便,对外提供的服务,一般使用基于HTTP的RESTful架构。
REST:以资源为中心的表述性状态转移(Representational State Transfer)。REST与RPC几乎没有任何关系。RPC是面向服务的,并关注于行为和动作;而REST是面向资源的,强调描述应用程序的事物和名词。
REST就是将资源的状态以最适合客户端或服务端的形式从服务端转移到客户端(或者反过来)。在REST中,资源通过URL进行识别和定位。REST的本质是面向资源的。
RPC框架作为架构微服务化的基础组件,它能大大降低架构微服务化的成本,提高调用方与服务提供方的研发效率,屏蔽跨进程调用函数(服务)的各类复杂细节。让调用方感觉就像调用本地函数一样调用远端函数、让服务提供方感觉就像实现一个本地函数一样来实现服务。
RPC的效率高,多用在系统之间的内部调用采用RPC。
1、分布式操作系统的进程间通讯
进程间通讯是操作系统必须提供的基本设施之一,分布式操作系统必须提供分布于异构的结点机上进程间的通讯机制,RPC是实现消息传送模式的分布式进程间通讯的手段之一。
2、构造分布式计算的软件环境
由于分布式软件环境本身地理上的分布性,,它的各个组成成份之间存在大量的交互和通讯,R P C 是其基本的实现方法之一。ONC+和DCE两个流行的分式布计算软件环境都是使用RPC构造的,其它一些分布式软件环境也采用了RPC方式。
3、远程数据库服务
在分布式数据库系统中,数据库一般驻存在服务器上,客户机通过远程数据库服务功能访问数据库服务器,现有的远程数据库服务是使用RPC模式的。例如,Sybase和Oracle都提供了存储过程机制,系统与用户定义的存储过程存储在数据库服务器上,用户在客户端使用RPC模式调用存储过程。