RPC-远程过程调用

什么是RPC

RPC,Remote Procedure Call,远程过程调用。
那么怎么去理解这个远程过程调用呢?我们可以先理解一下相对的本地过程调用。

本地过程调用

本地调用,很简单,通俗一点来说,就是你在你的项目中定义了一个函数,然后调用,这就是本地过程调用。

function add(x, y){
    return x + y;
}

const a = 1, b = 2;
const result = add(a, b) // 这就是本地过程调用

如上面代码所示,先是定义了一个add函数,在代码块最后一行调用add函数的过程其实就是本地过程调用。
那么最后一行代码的执行,在计算机中的过程是怎样的呢?

  1. 计算机解析函数名
  2. 通过最底层的块级作用域一直往上找寻找函数声明的地方
  3. 计算机寻址,从内存中找到存放该函数的地址
  4. 参数a和b入栈,执行函数逻辑
  5. 返回计算结果并赋值给result

ps:这只是简单描述了一下本地调用的过程,其实计算机内部或者浏览器V8引擎做了许多优化。

远程过程调用

那么上面讲了本地过程调用,远程过程调用其实是相似的,只是函数声明定义及其作用域在远端,别的机器,别的服务上,因为不存在共同的内存空间,所以不可以直接像本地调用一样寻找到该函数。

那么,对比本地调用,远程调用还需要额外解决什么问题呢?

1.通讯问题

相对于本地调用来说,不同服务和不同机器无法共用同样的内存空间,因此无法直接通讯。因此需要建立TCP连接,调用方和被调方的数据均是基于此连接中进行交换。像grpc的框架,底层tcp连接是基于http2.0协议的,其中的协议数据类型有unarystream两种,其中差异是客户端和服务端的通讯差异,底层还是通过二进制流拼凑的数据帧进行传输,并且在包头中会表明对应的数据类型。

  1. unary,通过一问一答的形式在客户端和服务端中进行通讯。
  2. stream,其中又分为客户端流、服务端流和双工流。
    ①客户端流:客户端发送多条数据流,服务端回答一条。
    ②服务端流:客户端发送一条数据流,服务端回答多条。
    ③双工流:客户端和服务端都可以主动向对方发送数据流。
2.寻址问题

基于第一步,两台机器中已经建立连接了,那么被调方怎么知道调用方想调用哪个服务的哪个接口呢?这里就需要在建立tcp连接进行数据传输的时候,需要调用方把被调方的ip、端口和函数id等信息带过去,这部分信息一般称为call ID映射。
一般来说,调用方和被调方都会维护一个映射表,里面包含了调用函数的入参和出参,这部分有点类似与接口协议。

3.序列化和反序列化

基于网络协议传输是二进制的形式,那么调用方传输的寻址信息和入参等数据需要序列化之后才能传输,而被调方先是反序列化数据,找到对应的函数,并在执行函数后将结果序列化后传回去给到调用方,最后调用方反序列化数据之后得到结果。
image.png
图片来源(https://www.cs.rutgers.edu/~pxk/417/notes/03-rpc.html)

为什么用RPC

相信很多同学都有疑问,为啥要用RPC协议?为啥不能继续用http/https协议进行传输呢?
其实大家陷进了一个理解误区,就是RPC和``不是两个平行的概念。
RPC只是一个函数调用,但是需要通过远程调用,因此底层通讯传输是基于TCP协议的。
HTTP协议是一个网络传输协议,底层也是基于TCP的,因此大家很容易产生误解。

那么为什么要用RPC进行呢?

1.RPC协议,客户端和服务端都会维护一份结构和映射表,使调用和传输的数据更透明,双方都可以更严格地制约调用参数和回包参数的类型,从而减少bug。

2.对TCP传输进行优化,如:二进制流传输,无用包头信息废除,包体压缩,字节编码解码优化等。其实基于HTTP2.0这些功能已经支持了,因此gRPC的TCP传输也是参考HTTP2.0的。

3.rpc结构层可以做更多的监控,容错和性能优化。

参考文章:
https://www.zhihu.com/question/25536695
https://www.zhihu.com/question/41609070


TheWalkingFat
522 声望32 粉丝