当前位置: 首页 > Linux

网络协议19-RPC协议:远在天上,近在咫尺

时间:2023-04-06 11:40:30 Linux

【前五篇】系列文章传送门:网络协议14-流媒体协议:说爱你不容易网络协议15-P2P协议:小种子就是大学习网络协议16-DNS协议:互联网世界中的通讯录网络协议17-HTTPDNS:个人定制的DNS服务网络协议18-CDN:门口小店这几年微服务很火,想必有比较多的博主都或多或少接触过。在微服务的概念中,服务之间的相互调用是不可或缺的一部分。你知道微服务是如何相互调用的吗?你可能会说,这不简单,用socket吧。服务分为调用者和被调用者,我们只需要建立TCP或UDP连接进行通信即可。聊着聊着,你可能会发现这件事并没有那么简单。让我们以最简单的场景为例:客户端调用一个加法函数,将两个整数相加并返回它们的和。如果是在本地调用,简单的不能再简单了,但是一旦变成远程调用,门槛一下子就上去了。首先你要懂socket编程,至少你得先把我们这个系列的所有协议都看懂,然后再厚厚的看N本socket编程的书,把我们学过的几种socket编程模型学一遍。这就让一份大学毕业就能做的工作,变成了五年工作经验都未必好做的工作。而且,搞定socket编程是万里长征的第一步。还有很多问题。存在问题问题一:如何指定远程调用的语法?客户端如何告诉服务器我是加法,另一个是减法。它是作为字符串“add”传递给你的,还是作为整数传递给你的,比如1表示加法,2表示减法?服务器应该告诉客户端这是加法,目前只能加整数,不能加小数和字符串。还有一个加法“add1”,可以实现小数和整数的混合加法,返回值是多少?正确时返回什么,错误时返回什么?问题2:如何传递参数?我应该先传递两个整数,然后传递一个操作数“add”,还是先传递运算符,然后再传递两个整数?另外,如果我们使用UDP进行传输,参数放在一个报文中是可以的,但是如果是TCP的话,就是一个流,这个流中前后两次调用怎么区分呢?问题三:如何表示数据?在我们的加法例子中,传递的是一个定长的int值,这很好,但是如果是一个变长类型,一个结构体,甚至一个类,我们该怎么办呢?就算是int,不同平台长度不一样,怎么办?问题四:如何知道服务器执行了哪些远程调用?从哪个端口可以访问这个远程调用?假设服务端实现了多个远程调用,每个实现可能不在同一个进程中,监听的端口不一样,而且由于服务端是自己实现的,不可能使用大家都认可的端口,而且是可能一台机器上部署了多个进程,每个人都需要抢占端口。为了防止冲突,通常使用随机端口。客户端如何找到这些监听端口呢?问题5:出现错误、重传、丢包、性能等问题怎么办?本地调用没有这个问题,但是一旦上了网络,这些问题就需要处理了,因为网络是不可靠的,虽然在同一个连接中,我们也可以通过TCP协议来保证丢包和重传的问题,但如果服务器Crashed重启,当前连接断开,TCP无法保证,应用需要重新调用自己。重传会不会是同一个操作两次,会不会影响远程调用性能?解决问题看到这么多问题,是不是很头疼?还记得我们学习http的时候,我们知道的协议的三要素吗?本地调用函数有很多问题,比如词法分析、句法分析、语义分析等,这些问题基本都是编译器帮我们解决的,但是在远程调用中,我们就得自己考虑这些问题了。agreement协议的问题很多公司针对这个问题有一个核心交流群,里面全是socket编程高手,实现了一个统一的库,供其他业务群的人调用。业务人员不需要知道中间传输的细节。通信双方的语法、语义、格式、端口、错误处理等需要与调用方和被调用方开会讨论,双方达成一致。一旦一方发生变化,必须及时通知另一方,否则就会出现问题。但是,并不是每个公司都能通过这种大团队解决问题,而是使用已经实现的框架。有个大牛(BruceJayNelson)通过一篇论文定义了RPC的调用标准。所有后续的RPC框架都遵循这个标准模式。整个过程如下:当客户端应用程序要发起远程调用时,实际上使用的是本地调用者的Stub。负责通过约定的协议规范对调用的接口、方法和参数进行编码,并通过本地RPCRuntime传输,将调用网络包发送给服务端;服务器的RPCRuntime收到请求后,交给提供者Stub进行编码。然后调用服务端的方法获取结果,对结果进行编码后发送给客户端;客户端的RPCRuntime收到结果,发送给调用者Stub解码结果,返回给客户端。上述过程分为三个层次:client、stub层、server。对于客户端和服务端来说,就像本地调用一样,只关注业务逻辑的处理。对于Stub层,处理双方约定的语法、语义、封装和解封装。对于RPCRuntime,主要处理高性能传输,以及网络错误和异常。RPC的最早实现之一称为SunRPC或ONCRPC。Sun是第一个提供商业RPC库和RPC编译器的公司。NFS协议中使用了此RPC框架。NFS(NetworkFileSystem)是一种网络文件系统。要使NFS成功运行,必须启动两台服务器,一台mountd,用于挂载文件路径。另一个是nfsd,用来读写文件。NFS可以在本地挂载一个远程目录到本地目录,这样当本地用户读写本地目录下的文件时,操作的是另一台远程机器上的文件。远程操作和远程调用的思路是一样的,就像本地操作一样,所以NFS协议是基于RPC实现的。当然不管RPC是什么,底层都是socket编程。XDR(ExternalDataRepresentation,外部数据表示)是一种标准的数据压缩格式,可以表示基本的数据类型和结构。这里有几种基本数据类型。RPC调用时,所有的数据类型都必须封装成相似的格式,RPC调用和结果返回也有严格的格式。XID唯一标识请求和回复。请求为0,回复为1;RPC有版本号,两端必须匹配RPC协议的版本号。如果不匹配,则返回拒绝,原因为RPC_MISMATCH;节目编号。如果服务器找不到该程序,将返回PROG_UNAVAIL;该程序有一个版本号。如果程序版本号不匹配,则返回PROG_MISMATCH;一个程序可以有多个方法,方法也有一个编号。如果找不到该方法,则返回PROG_UNAVAIL;调用需要鉴权鉴权,失败则返回Deny;finally是一个参数列表。如果无法解析参数,则返回GABAGE_ARGS;为了成功调用RPC,在客户端和服务端实现RPC时,首先要定义双方都认可的程序、版本、方法、参数等。对于上面的添加,双方同意一个协议定义文件。同样,如果是NFS,挂载和读写,也会有类似的定义。有了协议定义文件,ONCRPC将提供一个工具来生成基于此文件的客户端和服务器存根程序。最底层是XDR文件,用于编解码参数。这个文件是客户端和服务端共享的,因为只有双方都同意才能通信成功。在client端,它会调用clnt_create创建连接,然后调用add_1,是一个Stub函数,感觉调用的是本地函数。其实这个函数发起了一个RPC调用,通过调用clnt_call调用ONCRPC类库来真正发送请求。调用过程比较复杂,后面会具体说明。当然,服务端也有一个Stub程序,用来监听客户端的请求。调用到来时判断如果是add,则调用真正的server逻辑,就是把两个数相加。服务器将结果返回给服务器Stub,Stub程序将结果发送给客户端Stub,客户端Stub收到结果后将结果返回给客户端应用程序,从而完成调用。有了这个RPC框架,前五个问题“如何指定远程调用的语法?”,“如何传递参数?”和“如何表示数据?”传输问题‖‖‖前三个问题已经解决,但是错误、重传、丢包和性能问题还没有解决。我们将这些问题统称为传输问题。这个Stub层无奈,不过是ONCRPC类库实现的。在这个类库中,为了解决传输问题,会为每个客户端创建一个传输管理层,每次RPC调用都是一个任务。在传输管理层,可以看到熟悉的队列机制、拥塞窗口机制等。由于网络传输时经常需要等待,而同步的方式往往效率低下,所以也就出现了socket的异步模型。为了能够异步处理,远程调用的处理往往通过状态机来实现。只有当满足某个状态时,才会执行下一步。如果状态不满足,则不会在那里等待,而是保留资源用于处理其他RPC调用。如上图所示,从图中也可以看出,这个状态转移图还是很复杂的。首先进入初始状态,检查RPC传输层队列中是否有空闲位置,可以处理新的RPC任务,如果没有,说明太忙,结束或重试。如果申请成功,就可以分配内存,获取服务器的端口号,然后连接到服务器。连接过程需要一段时间,因此您必须等待连接结果。如果连接失败,直接结束或者重试。如果连接成功,开始发送RPC请求,然后等待获取RPC结果。同样,这个过程也需要时间。如果发送有误,将重新发送。如果连接断开,则必须重新连接。如果超时,则必须重传。如果得到结果,就可以解码,正常结束。这个处理了连接失败、重试、发送失败、超时、重试等场景。因此,实现一个RPC框架其实是非常困难的。服务发现问题传输问题解决了,但是我们还有一个“如何找到RPC服务器的随机端口”的问题,我们称之为服务发现问题。在ONCRPC中,服务发现是通过portmapper实现的。portmapper将在一个众所周知的端口上启动。由于RPC程序是用户写的,它会监听一个随机的端口,但是RPC程序启动时,会向portmapper注册。当客户端要访问RPC服务器程序时,首先查询portmapper获取RPC服务器程序的随机端口,然后与该随机端口建立连接,开始RPC调用。从下图可以看出,挂载命令的RPC调用就是这样实现的。总结远程调用看似使用socket编程就可以了,其实很复杂。需要解决协议约定问题、传输问题和服务发现问题;ONCRPC框架和NFS的实现给出了解决上述三个问题的实现,即公共协议描述文件,并通过该文件生成Stub程序。RPC传输一般需要一个状态机和另一个专用于服务发现的进程。参考:刘超-浅谈网络协议系列;如何向我的妻子解释什么是RPC;