Home RPC框架

0 29

写代码之前,我想先整理一下思路。

假设你在开发一款《学生成绩管理系统》的web应用时,你对自己的开发内容是十分清楚的:

  1. web应用是B/S架构;B/S模式是指基于浏览器(Browser)服务器(Server)形式的应用
  2. 正因为web应用是B/S架构,所以你需要编写一些好看的网页,并使得这些网页具有功能入口,这部分称之为前端工作。
  3. 前端工程展示在浏览器上,那浏览器上的数据从何而来?往何处而去?答案就是服务器。因此,你需要将后端工程部署到服务器上使之运行,同时还需要在服务器上配置MySQL,Redis等。

不管先写前端还是先写后端,还是先去部署MySQL这样的服务到服务器上,至少你清楚你要做的事情。

可是面对RPC框架,我还不知道要做什么。我的解决办法是:从应用的核心功能出发去思考,即——远程方法调用。

根据RPC框架中角色的定义:

客户端(Client):服务调用方。最理想的情况是RPC Client在完全不知道有RPC框架存在的情况下发起对远程服务的调用。

服务端(Server):服务提供方。在RPC规范中,这个Server并不是提供RPC服务器IP、端口监听的模块。而是远程服务方法的具体实现(在JAVA中就是RPC服务接口的具体实现)。其中的代码是最普通的和业务相关的代码,甚至其接口实现类本身都不知道将被某一个RPC远程客户端调用。

至此,我们只需要牢记一个概念,RPC框架是支持客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个资源(该资源由服务端实现),就像调用本地应用程序中的资源一样的框架。框架中的所有细节所有技术,都是为了实现这个概念。

为此,我们可以奠定我们开发的核心内容:

  1. 实现客户端
  2. 实现服务端
  3. 实现客户端对服务端提供的远程服务的调用

让我们从最简易的实现开始,一步步的去完善这个框架的细节,支持更多的功能~

0 30

准备秋招时看到Guide哥的RPC框架,感觉这个项目应该会很有竞争力,可惜还没来得及学习秋招就已经结束了,因此将其作为我的毕业设计项目。

 

RPC(Remote Procedure Call):远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想

通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个资源,就像调用本地应用程序中的资源一样。

RPC框架屏蔽了实现细节,使得开发者的操作变得简单,不仅达到了远程过程调用的目的,还实现了服务发现、负载、容错、网络传输、序列化等功能。

RPC(Remote Procedure Call Protocol)远程过程调用协议。一个通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个对象,就像调用本地应用程序中的对象一样。比较正式的描述是:一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。那么我们至少从这样的描述中挖掘出几个要点:

  • RPC是协议:既然是协议就只是一套规范,那么就需要有人遵循这套规范来进行实现。目前典型的RPC实现包括:Dubbo、Thrift、GRPC、Hetty等。这里要说明一下,目前技术的发展趋势来看,实现了RPC协议的应用工具往往都会附加其他重要功能,例如Dubbo还包括了服务管理、访问权限管理等功能。
  • 网络协议和网络IO模型对其透明:既然RPC的客户端认为自己是在调用本地对象。那么传输层使用的是TCP/UDP还是HTTP协议,又或者是一些其他的网络协议它就不需要关心了。既然网络协议对其透明,那么调用过程中,使用的是哪一种网络IO模型调用者也不需要关心。
  • 信息格式对其透明:我们知道在本地应用程序中,对于某个对象的调用需要传递一些参数,并且会返回一个调用结果。至于被调用的对象内部是如何使用这些参数,并计算出处理结果的,调用方是不需要关心的。那么对于远程调用来说,这些参数会以某种信息格式传递给网络上的另外一台计算机,这个信息格式是怎样构成的,调用方是不需要关心的。
  • 应该有跨语言能力:为什么这样说呢?因为调用方实际上也不清楚远程服务器的应用程序是使用什么语言运行的。那么对于调用方来说,无论服务器方使用的是什么语言,本次调用都应该成功,并且返回值也应该按照调用方程序语言所能理解的形式进行描述。

那么上面的描述情况可以用下图表示:

2-2、RPC要素

当然,上图是作为RPC的调用者所观察到的现象(而实际情况是客户端或多或少的还是需要知道一些调用RPC的细节)。但是我们是要讲解RPC的基本概念,所以RPC协议内部是怎么回事就要说清楚:

  • Client:RPC协议的调用方。就像上文所描述的那样,最理想的情况是RPC Client在完全不知道有RPC框架存在的情况下发起对远程服务的调用。但实际情况来说Client或多或少的都需要指定RPC框架的一些细节。
  • Server:在RPC规范中,这个Server并不是提供RPC服务器IP、端口监听的模块。而是远程服务方法的具体实现(在JAVA中就是RPC服务接口的具体实现)。其中的代码是最普通的和业务相关的代码,甚至其接口实现类本身都不知道将被某一个RPC远程客户端调用。
  • Stub/Proxy:RPC代理存在于客户端,因为要实现客户端对RPC框架“透明”调用,那么客户端不可能自行去管理消息格式、不可能自己去管理网络传输协议,也不可能自己去判断调用过程是否有异常。这一切工作在客户端都是交给RPC框架中的“代理”层来处理的。
  • Message Protocol:在上文我们已经说到,一次完整的client-server的交互肯定是携带某种两端都能识别的,共同约定的消息格式。RPC的消息管理层专门对网络传输所承载的消息信息进行编号和解码操作。目前流行的技术趋势是不同的RPC实现,为了加强自身框架的效率都有一套(或者几套)私有的消息格式。例如前文所讲到的RMI框架使用的消息协议为JRMP;后文我们将详细讲解的RPC框架Thrift也有私有的消息协议,“- Transfer/Network Protocol”(当然它还支持一些通用的消息格式,如JSON)。
  • Transfer/Network Protocol:传输协议层负责管理RPC框架所使用的网络协议、网络IO模型。例如Hessian的传输协议基于HTTP(应用层协议);而Thrift的传输协议基于TCP(传输层协议)。传输层还需要统一RPC客户端和RPC服务端所使用的IO模型;常用的IO模型在之前已经详细讲解过了(可参见我之前的博文《架构设计:系统间通信(3)——IO通信模型和JAVA实践 上篇》)
  • Selector/Processor:存在于RPC服务端,由于服务器端某一个RPC接口的实现的特性(它并不知道自己是一个将要被RPC提供给第三方系统调用的服务)。所以在RPC框架中应该有一种“负责执行RPC接口实现”的角色。它负责了包括:管理RPC接口的注册、判断客户端的请求权限、控制接口实现类的执行在内的各种工作。
  • IDL:实际上IDL(接口定义语言)并不是RPC实现中所必须的。但是需要跨语言的RPC框架一定会有IDL部分的存在。这是因为要找到一个各种语言能够理解的消息结构、接口定义的描述形式。如果您的RPC实现没有考虑跨语言性,那么IDL部分就不需要包括,例如JAVA RMI因为就是为了在JAVA语言间进行使用,所以JAVA RMI就没有相应的IDL。
  • 一定要说明一点,不同的RPC框架实现都有一定设计差异。例如生成Stub的方式不一样,IDL描述语言不一样、服务注册的管理方式不一样、运行服务实现的方式不一样、采用的消息格式封装不一样、采用的网络协议不一样。但是基本的思路都是一样的,上图中的所列出的要素也都是具有的。

文章链接:架构设计:系统间通信(10)——RPC的基本概念 – 云+社区 – 腾讯云 (tencent.com)