「RPC」简述RPC

RPC是什么

RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TPC/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。

过程是什么?

过程就是业务处理、计算任务,更直白的说,就是程序,就是想调用本地方法一样调用远程的过程

进程间通信(IPC)是在多任务操作系统或联网的计算机之间运行的程序和进程所采用的通信技术,IPC有两种类型的进程间通信的方式分别是本地过程调用(LPC)和远程过程调用(RPC)。

本地过程调用LPC

本地过程调用(LPC)用于多任务操作系统中,使同时运行的任务能够相互会话,任务共享内存空间以实现任务同步和互相发送消息。

例如:完成一个本地函数的调用

int add(int x, int y){
  return x + y;
}
int a = 1;
int b = 2;
int result = add(a, b);

add()函数的执行流程

  1. 分别将变量a和b的值压入栈

  1. 执行add()函数,从栈中取出a和b的值,赋值给x和y。

  1. 计算x加y的值并保存到栈中

  1. 退出add()函数将x加y的值赋值给result

本地过程调用发生在同一进程中,共享内存区域。而RPC通信则需要跨域不同机器、不同进程,因此需要解决三个问题:函数ID(服务寻址)、数据流的序列化和反序列化、网络传输

如果add()函数调用在客户端,执行函数的函数体却在远程机器上,如何告知机器如何调用这个方法呢?

首先客户端需要告诉服务器,需要调用的函数,这里函数和进程ID存在一个映射,客户端远程调用时需要检查一下函数以找到对应的ID,然后执行函数的代码。

客户端需要将本地参数传递给远程函数,本地调用的过程中直接压栈即可。但在远程调用过程中不在同一个内存中,无法直接传递参数的参数,因此需要客户端将参数转换为字节流,传递给服务器。服务器再将字节流转换为自身能读取的格式,这是一个序列化和反序列化的过程。

当数据准备好之后,如何进行传输呢?网络传输层需要将调用的ID和序列化后的参数传递给服务器,然后将计算好的结果序列化传递给客户端。因此TCP层可以完成上述操作。那么为什么不使用HTTP层呢?由于HTTP在应用层中完成,整个通信的代价比较高,RPC直接基于TCP进行远程调用,数据传输在传输层TCP完成,更加适合对效率要求比较高的场景。RPC主要依赖于客户端和服务器之间建立的Socket链接进行,但底层实现比REST更为复杂

远程过程调用RPC

远程过程调用(RPC)类似于LPC,只是在网络中工作,RPC开始是出现在SUN微系统公司和HP公司运行的UNIX操作系统中。

RPC的概念与技术早在1981年由Neison提出,1984年Birrel和Neison将其用于支持异构型分布式系统的通讯。Birrell的RPC模型引入存根进程(stub)作为远程的本地代理,调用RPC运行时库来传递网络中的调用。Stub和RPC runtime屏蔽了网路所涉及的细节。特别是参数编码与转码以及网络任务的多样性。RPC作为网络通讯与委托计算的实现机制,在方法、协议、语义和实现上不断发展,种类繁多,其中SUN公司和开发软件基金会在分布式产品中所建立和使用的RPC较为典型。

RPC(Romote Procedure Call)远程过程调用,RPC是通信协议,该协议允许运行于一台计算机的程序调用另一台计算机的子程序,开发人员无需额外为交互作用编程。若软件采用面向对象编程,那么RPC又称为远程调用或远程方法调用。简单来说,远程调用协议是一种通过网络从远程计算机程序上请求服务,同时无需了解底层网络技术的协议。

RPC是一种用于构建基于客户端/服务器(C/S)的分布式应用程序技术,调用者与被调用者可能在同一台服务器上,也可能在由网络连接的不同服务器上。对客户端和服务器而言,使用RPC时网络通信是透明的,远程调用如何本地调用一样简单。简单来说,RPC就是要像调用本地函数一样去调用远程函数。

RPC解决了什么问题?

  1. 解决分布式系统中,服务之间的调用问题。

  1. 远程调用时,能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。

为什么需要RPC?

  1. RPC可以用HTTP协议实现,HTTP是建立在TCP之上最广泛使用的RPC,互联网公司往往会使用自己的私有协议,比如腾讯的JCE协议,私有协议不具备通用性,但相比HTTP协议,RPC采用二进制字节码传输,更加高效也更为安全。

  1. 业界提倡的微服务中,服务之间通信方式中RPC是其中之一,RPC可以保证不同服务之间的相互调用,即使是跨语言跨平台也不是问题,让构建分布式系统更为容易。

  1. RPC框架都会存在服务降级、流量控制的功能,以保证服务的高可用。

RPC其实是一种技术思想而非规范或协议,常见RPC技术和框架有

  • 应用级的服务框架:阿里的Dubbo/Dubbox、Google的gRPC、Spring Boot/Spring Clound

  • 远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)

  • 通信框架:MINA、Netty

和本地调用有什么区别

远程调用,就好像异地恋一样,隔着千山万水

本地调用,就是女生就在你身边,近水楼台先得月

远程调用之间需要通过网络,所以响应要慢几个数量级,也不那么可靠


平时写程序中我们常常会用到函数调用,而一般的函数调用都在同一个进程内。但如果现在要求某个函数去调用另个工程里的一个函数,该怎么办呢?

我最先想到的是http服务,编写RESTful风格的url并通过http请求传递参数从而获得远程工程的响应,这个方法可以很方便的在两个程序间保持通讯。

如A工程下的a方法调用B工程下的b方法:

但有没有办法可以向本地调用那么畅快呢?不用在B工程下搭建http服务器,进行构建url、序列化/反序列化数据等一系列操作,就直接了当的像下面这样

function a() {
    ...
    B.b()
    ...
}

RPC模式

RPC采用客户端/服务端的模式,通过request-response消息模式实现

RPC的三个过程

1:通讯协议

比如:你需要找人在国外干活,那么你可以直接飞过去或者打电话或者通过互联网的形式,去找人,这个找人的过程就是通讯协议

2:寻址

既然要找人干活,肯定要知道地址在哪,飞过去需要找到详细地址,打电话需要知道电话号码,互联网需要知道IP是多少

3:数据序列化

就是说,语言需要互通,才能够让别人干活,之间需要一个大家都懂的语言去交流

为什么要使用RPC

1:服务化/微服务

2:分布式系统架构

3:服务可重用

4:系统间交互调用

RPC和其他协议的区别

RMI远程方法调用是RPC的一种具体实现,webservice、restfull都是RPC,只是消息的组织形式、消息协议不同

rpc与http的区别

可是rpc服务相较于http服务在网间通讯上有什么优势呢?

1. http服务使用HTTP协议传输数据,其的header会在消息中占很大比例,由于接收方不是浏览器,因此这部分就是废信息,完全是在浪费带宽。而rpc服务普遍基于TCP协议,自定义了消息格式,携带很少的无用信息,具有很高效率。但2015年推出的HTTP2.0协议会对header做压缩,故使用HTTP2.0来传输数据也可以接受。

2. rpc服务普遍基于TCP协议,http服务则基于HTTP协议。我们知道在计算机网络的工业实现中一般采用4层模型,从上至下依次为:应用层,传输层,网络层,链路层。

TCP协议位于传输层,而HTTP协议则基于TCP协议,位于应用层中。因此相较于rpc服务直接使用TCP协议包装,http服务则需依次经过HTTP与TCP的两次包装,速度不言而喻。

3. rpc服务使用长链接,相较于http服务的短链接,避免大量三次握手所带来的性能下降。

这条理由目前已没那么重要了,在HTTP1.0中需要keep-alive来建立长连接,HTTP1.1默认长连接,HTTP2.0支持多路复用,即一个连接处理多个请求,这一系列举动在于尽量避免http服务建立连接时的过多握手。目前觉得这点可能不会太影响效率,并且Google的rpc框架GRPC就是基于HTTP2.0的。

从上面三点可以看出,相较于http服务,rpc服务具有更快的速度,并所需更小的带宽。

4. rpc服务内部直接指明服务器ip,且传输的数据是经过自己编码过的,因此具有更高的安全性。可以认为采用http传递信息是在讲普通话,而rpc则是讲团队黑话,具有更高的保密性。

5. rpc服务有许多现成的rpc框架,我们自己只需去实现服务器端的一些处理函数。有关读写网络内容,使用传输协议序列化/反序列化数据,处理器调用等操作框架会自动处理,我们不必操心。并且rpc框架还封装了错误重试等特性,针对服务的稳定性和可靠性都做了优化,而单纯的http服务是没有这些特性的。

到底选择http服务或rpc服务来传递数据,还是要看具体工程,没有绝对好坏之分,但rpc确实适合大型项目不同工程间的内部调用。另外说一下,在http服务器上增加一层封装,也就变成了rpc服务,比如Google的GRPC框架。

rpc的架构

rpc是典型的客户端/服务器模式,请求发起者是客户端,而服务提供者是服务器。客户端与服务器之间需要事先约定好传输方式与编码协议。

个人感觉一个rpc框架逃不开四大核心组件:Client、Server、Client Stub、Server Skeleton。

1)Client:客户端,服务的调用方

2)Server:服务端,服务的真正提供者

3)Client Stub:客户端存根,存放有服务器地址,其将客户端的请求打包后通过网络发给服务方

4)Server Skeleton:服务端存根,用于接收客户端发来的消息,将消息解包后调用服务端本地方法,并将本地方法的返回值打包后回复给客户端

其中的存根可以理解成是接口,即需要自己编写代码去实现。其目的是屏蔽客户端调用远程主机上某个对象的过程,其提供某种方式在本地模拟远程对象,负责接收本地方法的调用,并将请求委派给远端的具体执行对象。

上面的这段描述可能有些绕,下面稍作解释(A工程下的a方法调用B工程下的b方法)

使用rpc时,A工程为客户端,B工程为服务端。为了使B工程下的b方法在a方法中可被调用,我们会在A工程里为b方法搞个替身c。

c方法一旦被调用,其会调用客户端的stub,stub通过网络调用服务端的skeleton,而skeleton则调用并返回本地b方法的执行结果。由此,a方法在调用客户端c方法的时候,感觉上就是直接调用了远端服务器的b方法。

使用rpc的步骤

虽然可供选择的rpc框架非常多,但使用的大体流程似乎都差不多:

1. 使用类似的IDL(接口描述语言)定义数据结构和接口

2. 选择目标语言,用框架的代码生成引擎生成rpc的客户端,服务端,客户端存根,服务端存根等代码

3. 配置客户端与服务器,将响应客户端请求的处理器与目标服务相绑定,也就是这个绑定过程需要开发者编写一些代码

RPC核心功能

RPC核心功能是指实现一个RPC最重要的功能模块即RPC协议部分,一个RPC的核心功能主要由5部分组成分别是:客户端、客户端存根Stub、网络传输模式、服务器、服务器存根Stub。

  • 客户端:服务调用方

  • 客户端存根:存放服务器地址信息,将客户端请求参数数据打包成网络消息,在通过网路传输发送给服务器。

  • 网络传输模式:底层传输,可以是TCP或HTTP。

  • 服务器存根:接受客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。

  • 服务器:服务的真正提供者

RPC技术点

实现RPC重点需要实现三个技术,分别是:服务寻址、数据流的序列化和反序列化、网络传输

服务寻址

服务寻址可以使用Call ID映射,在本地调用中,函数体是直接通过函数指针来指定的,但在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以在RPC中所有的函数都必须具有自己的ID,这个ID在所有进程中都是唯一的。

客户端在做远程过程调用时,必须附上这个函数ID,还需要在客户端和服务端分别维护函数和Call ID的对应表。当客户端需要进行远程调用时,会差这个对应表找出对应的Call ID,然后将其传递给服务器,服务器也通过查对应表来确定客户端需要调用的函数,最终执行相对应函数的代码。

序列化和反序列化

客户端如何将参数传递给远程的函数呢?在本地过程调用中,只需要将参数压入栈,让函数自己去栈中读取即可。但在远程过程调用中,客户端跟服务器是不同的进程,不能通过内存来传递参数。此时就需要客户端将参数先转换为字节流再传递给服务器,服务器接收后再将字节流转换为自己能读取的格式。而在网络中只有二进制数据才能传输,因此序列化与反序列化的定义也就是将对象转换成二进制流的过程是序列化,将二进制转换为对象的过程则是反序列化。

网络传输

远程调用往往使用在网络环境中,客户端和服务器是通过网络连接的,所有的数据都需要通过网络传输,因此需要一个网络传输层。网络传输层需要将Call ID和序列化后的参数字节流传递给服务器,然后再将序列化后的调用结果传回给客户端。只要能完成这两个操作,都可以作为传输层使用。因此它所使用的网络传输协议是不限的,只要能完成传输即可。尽管大部分RPC框架都是用TCP协议,其实UDP也可以。

TCP连接是最常见的,通常TCP连接可以是按需连接,即需要调用时先建立调用后断开。也可以是长连接,客户端和服务器建立连接后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制和定期检测建立的连接是否存活有效。另外,多个远程过程调用可以共享同一个连接。

简单来说,实现一个RCP框架只需要实现三点:

  • Call ID映射:可以直接使用函数字符串,也可以使用整数ID,映射表通常是要一个哈希表。

  • 序列化和反序列化:可使用Protobuf、FlatBuffers等之类

  • 网络传输库:可使用Socket、Asio、ZeroMQ、Netty等

RPC网络传输协议

在RPC中可选的网络传输方式有很多种,可选的包括TCP、UDP、HTTP,每种协议对整体的性能和效率都有不同的影响。如何选择一个正确的网络传输协议呢?

  • 基于TCP的RPC

基于TCP协议的RPC调用是由服务调用方和服务提供方建立Socket连接,并由服务调用方通过Socket将需要调用的接口名称、方法名称、参数序列化后传递给服务提供方,服务提供方反序列化后再利用反射调用相关的方法。最后将结果返回给服务调用方,整个基于TCP协议的RPC调用大致如此。

  • 基于HTTP的RPC

基于HTTP的RPC累加类似于访问网页,只是它返回的结果更为单一简单。首先由服务调用者向服务提供者发送请求,这种请求可能是GET、POST、PUT、DELETE等其中的一种,服务提供者可能会根据不同请求方式做出不同处理,或者某个方法只允许某种请求方式。调用的具体方法则根据URL进行方法调用,方法所需参数可能是对服务器调用方传输过去的XML或JSON数据解析后的结果,最后返回JSON或XML的数据结果。

两种方式对比

基于TCP实现的RPC由于TCP处于协议栈的下层,能够更加灵活地对协议字段进行定制,减少网路开销提高性能,实现更大的吞吐量和并发数。但需要更多关注底层复杂的细节,实现代价更高。同时对不同平台比如安卓、iOS等需要重新开发不同的工具包来进行请求发送和相应的解析,因此工作量大且难以快速响应和满足用户需求。

基于HTTP实现的RPC则可以使用JSON和XML格式的请求或响应数据,JSON和XML作为通用的格式开源解析工具已经相当成熟。但由于HTTP是上层协议,发送包含同等内容信息传输所占用的字节数会比TCP更高。

因此在同等网络下通过HTTP传输相同的内容效率会比TCP要低,信息传输所占的时间也会更长,虽然压缩数据能够减少这一差距

RPC工作原理

一次客户端对服务器的远程过程调用,其内部操作可分为以下步骤:

RPC调用流程

图中1-10序号的含义如下:

(1) Client像调用本地服务似的调用远程服务;

(2) Client stub接收到调用后,将方法、参数序列化

(3) 客户端通过sockets将消息发送到服务端

(4) Server stub 收到消息后进行解码(将消息对象反序列化)

(5) Server stub 根据解码结果调用本地的服务

(6) 本地服务执行(对于服务端来说是本地执行)并将结果返回给Server stub

(7) Server stub将返回结果打包成消息(将结果消息对象序列化)

(8) 服务端通过sockets将消息发送到客户端

(9) Client stub接收到结果消息,并进行解码(将结果消息发序列化)

(10) 客户端得到最终结果。

基于RPC的开发在在工作中主要用的最多的一个是基于Dubbo协议相关的开发方式,其中注册中心主要使用的是Zookeeper,还有一个就是相关的基于对应的RestFul风格的接口在,相关的开发的过程中,需要针对相关的功能模块开发,在后续的开发过程中,其中在进行相关的开发的时候,针对具体的RPC调用还是比较简单的,基本的@Feign或者走Dubbo都是可以进行开发的

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值