RPC概念

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

RPC采用客户机/伺服器模式。请求程序就是一个客户机,而服务提供程序就是一个伺服器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在伺服器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,伺服器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

RPC就是要像调用本地的函数一样去调远程函数。在研究RPC前,我们先看看本地调用是怎么调的。接下来我们介绍下本地过程调用的原理,相比大多数程序猿都了解一二;

本地过程调用

假设我们要调用函数Add来计算iValueA + iValueB的结果:

private int Add(int iA, int iB)
{
int iRet = iA + iB;
return iRet;
}

// Main函数中调用如下:
int iValueA = 1;
int iValueB = 2;
int iTotalAB = Add(iValueA, iValueB);

那么在最后一行时,我们实际上执行了以下操作:

  1. 将 iValueA 和 iValueB的值压栈
  2. 进入Add函数,取出栈中的值1 和 2,将其赋予 iA 和 iB
  3. 执行第2行代码,计算 iA + iB ,并将结果存在 iRet
  4. 将 iRet 的值压栈,然后从Add返回
  5. 最后一行,从栈中取出返回值 3 ,并赋值给 iTotalAB

以上5步就是执行本地调用的过程。

远程过程调用

在远程调用时,我们需要执行的函数体是在远程的机器上的,也就是说,Add是在另一个进程中执行的。这就带来了几个本地过程调用不具备的问题:

Function ID映射

疑问:我们怎么告诉远程机器我们要调用Add,而不是Sub或者Mul呢?

本地过程调用中,函数体是直接通过函数指针来确定的,我们执行Add函数,编译器会通过函数指针找到它。

远程过程调用中,通过函数指针是不行的,因为他们处于两个不同的进程中,不同进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一的。客户端在做远程过程调用时,必须附上这个ID。然后我们还需要在客户端(伺服器)和服务端分别维护一个 {函数 <--> Function ID} 的对应表(Map或Dictionary)。两者的表不一定需要完全相同,但相同的函数对应的Function ID必须相同。当客户端(伺服器)需要进行远程调用时,它就查一下这个表,找出相应的Function ID,然后把它传给服务端,服务端也通过查表,来确定客户端(伺服器)需要调用的函数,然后执行相应函数的代码。

序列化和反序列化

疑问:客户端如何把参数值传给远程的函数呢?

本地过程调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。

远程过程调用时,很显然前面我们已经提过了,客户端(伺服器)跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端(伺服器)和服务端使用的都不是同一种语言(比如服务端用C++,客户端(伺服器)用Java或者JavaScript)。这时候就需要客户端(伺服器)把参数先转成一个位元组流,传给服务端后,再把位元组流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。(序列化我经常用的就是Google的Protobuf和Json,它们两个在不同的应用场景各有优略,再此就不做讲解了)

网路传输

远程调用往往用在网路上,客户端(伺服器)和服务端是通过网路连接的(分散式网路伺服器)。所有的数据都需要通过网路传输,因此就需要有一个网路传输层。网路传输层需要把Function ID和序列化后的参数位元组流传给服务端,然后再把序列化后的调用结果传回客户端(伺服器)。只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,例如腾讯开源tars(Tencent/Tars)就支持TCP和UDP,另外有很多框架是支持SocketIO和WebSocket的,例如网易的Pomelo和Github上Dnode,都是很好的开源框架,再次就不做太多讲解了,可以自己找一个学习一下;

如果您要自己实现一套RPC框架,只需要做到以上三点就够了。


推荐阅读:
相关文章