浅谈远程过程调用——RPC

在复习SpringCloud的时候总是会遇到RPC这一词,但又不知道是何方神圣,上网冲浪了解了一下RPC,在此记录下对RPC的初步认识。

1. 什么是RPC

1.1 本地过程调用

如果我们需要将本地的Student对象的age加1,那么就需要写一个Student addAge(Student student)方法,将student对象作为形参传入,将student的年龄进行+1,再返回student对象即可。这个过程我们称作本地过程调用。本地过程调用的函数体通过函数指针来指定。

1.2 远程过程调用

那么如果addAge()方法的方法体不在本地,而是在另外一台服务器上,该怎么办呢?

也就是说有两台机器,一台服务器A,一台服务器B,一个应用部署在服务器A上,想要调用服务器B上的应用提供的方法,但是因为不在同一个服务器上,不能直接调用,这个时候就需要通过网络来表达调用的语义和需要传达的数据。

这个过程称作远程过程调用,而RPC就是远程过程调用(Remote Procedure Call)的缩写形式。

1.3 RPC概念总结

RPC即远程过程调用,通过RPC,我们可以像调用本地方法一样去调用远程机器上的方法。

2. RPC所解决的问题

2.1 需要调用什么方法?

2.1.1 Call ID映射

我们怎么让远程机器知道我们要调用的是什么方法呢?为什么是addAge()而不是addMoney()?

在本地调用中,我们通过函数指针去来指定对应的函数体,但是在远程调用中,函数指针是不可行的,因为我们所需要执行的函数体是在另外一台机器上的,也就是说addAge()是在另外一个进程中的,两个进程的内存空间是不一样的,所以函数指针不可行。

在RPC中,所有的函数/方法都会存在一个自己的Call ID,这个Call ID在每个进程中的都是唯一确定的,而且每个进程需要维护一个{函数体 ↔ Call ID}的对应表。不同进程的表可以不同,但对应的函数的Call ID必须相同,也就是说 ,同一个函数,同一个Call ID

在远程调用的时候,当前进程进行查表,找出该函数对应的Call ID,然后把Call ID传递给远程机器,远程机器再通过查表,找出Call ID对应的函数,然后执行相应函数的函数体。

2.2 参数值以什么形式传递?

2.2.1 序列化和反序列化

在上文中,我们提到了将Call ID传递给远程机器,而且大多数情况下我们还需要传递一些参数给远程机器,那么怎么传递呢?

在本地过程调用中,我们只需要将参数压入栈中,然后函数再将参数从栈中弹出来即可,但是远程调用的时候,不同的进程,不同的内存空间,是无法通过内存进行参数传递的,甚至可能两个进程使用的不是同一种语言(一个为Python、一个为Java)。

在PRC中,客户端会将参数序列化成一个字节流,传给服务端,服务端再将字节流反序列化为自己可以读取的格式,这个过程称作序列化反序列化

简而言之:客户端和服务端通过序列化和反序列化对参数进行处理

2.3 怎么传递参数值?

2.3.1 网络

将参数值进行序列化后怎么传递给远程机器呢?

远程调用往往用在网络上,客户端与服务端通过网络进行连接,所有的数据经过序列化成字节流后,通过网络传递给服务端。

所有的数据通过网络进行传递,因此就需要一个网络传输层,网络传输层需要把 Call ID 和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。

只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。

尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 干脆就用了 HTTP2。

TCP的连接是最常见的,大部分都通过TCP进行连接,简要分析下TCP连接:TCP连接可以是按需连接的(即需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接的(即维持连接的状态不变,不管是否有数据报的发送,可以配合心跳检测判定连接是否存活),多个远程过程调用共享同一个连接。

image-20200929201826064

3.网络传输协议

上文说明了要实现一个 RPC,需要选择网络传输的方式。

在 RPC 中可选的网络传输方式有多种,可以选择 TCP 协议、UDP 协议、HTTP 协议。

每一种协议对整体的性能和效率都有不同的影响,我们需要选择一个正确的网络传输协议。

3.1 基于 TCP 协议的 RPC 调用

由服务的调用方与服务的提供方建立Socket连接,并且由服务的调用方通过Socket将调用的接口名称、参数、方法名称序列化后传递给服务的提供方,服务的提供方反序列化后利用反射去调用相关的方法。

将结果返回给服务的调用方,整个基于 TCP 协议的 RPC 调用大致如此。

但是在实例应用中则会进行一系列的封装,如 RMI 便是在 TCP 协议上传递可序列化的 Java 对象。

3.2 基于HTTP协议的RPC调用

该方法更像是访问网页一样,只是它的返回结果更加单一简单。

其大致流程为:由服务的调用者向服务的提供者发送请求,这种请求的方式可能是 GET、POST、PUT、DELETE 等中的一种,服务的提供者可能会根据不同的请求方式做出不同的处理,或者某个方法只允许某种请求方式。

而调用的具体方法则是根据 URL 进行方法调用,而方法所需要的参数可能是对服务调用方传输过去的 XML 数据或者 JSON 数据解析后的结果,返回 JOSN 或者 XML 的数据结果。

由于目前有很多开源的 Web 服务器,如 Tomcat,所以其实现起来更加容易,就像做 Web 项目一样。

3.2 两种方式的对比

基于 TCP 的协议实现的 RPC 调用,由于 TCP 协议处于协议栈的下层,能够更加灵活地对协议字段进行定制,减少网络开销,提高性能,实现更大的吞吐量和并发数。(其实这一段我不太理解,源于我脆弱的计算机网络基础)

但是需要更多关注底层复杂的细节,实现的代价更高。同时对不同平台,如安卓,iOS 等,需要重新开发出不同的工具包来进行请求发送和相应解析,工作量大,难以快速响应和满足用户需求。

基于 HTTP 协议实现的 RPC 则可以使用 JSON 和 XML 格式的请求或响应数据。

而 JSON 和 XML 作为通用的格式标准(使用 HTTP 协议也需要序列化和反序列化,不过这不是该协议下关心的内容,成熟的 Web 程序已经做好了序列化内容),开源的解析工具已经相当成熟,在其上进行二次开发会非常便捷和简单。

但是由于 HTTP 协议是上层协议,发送包含同等内容的信息,使用 HTTP 协议传输所占用的字节数会比使用 TCP 协议传输所占用的字节数更高。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值