图片

容器之间的调用已经说了,服务之间的调用还没有说明,如何实现呢?

服务之间分调用方和被调用方,建立一个TCP和UDP的连接,是这样吗?

图片

那么,使用本地的调用,很简单,但是一旦变为了远程调用,门槛就上去了

首先是要Scoket编程,然后将这几种网络协议学一下,然后在学习很多高深的Socket编程知识,才能进行万里长征的第一步,后面还有着很多的问题

那么对于彼此Socket互联,会出现五个问题

这五个问题为

1.如何规定远程调用的语法

比如,如何告诉服务端,我需要使用加法,是先传入add字符串,还是传入一个整数,用1表示 +呢?

服务端如何告诉客户端,我这个加法,只能加整数,不能加小数呢?而另外的一个add 2 ,可以实现小数和整数的混合加法,返回值又是什么?正确的时候返回什么,错误的时候返回什么

2.如何传递正确的函数参数呢?

对于调用方法,是先传入两个整数,然后传入一个操作符add呢?还是先传入操作符add,再传入两个整数呢?如果想要实现一个逆波兰表达式,是如何传入呢?

3.如何表示正确的数据呢?

对于一个固定长度的int值,如何传递,这样解决了,还有着编程的数据类型,而且,对于一个int,不同的平台上长度也不一样,怎么办?

比如:Big Endian和Little Endian的问题

我们要在32位的四个Byte的一个空间存放一个整数1,只要有一个Byte中存了1,就可以了,那么问题就是,是第一个Byte放1,还是最后一个Byte放1呢?

最后一位放,叫做Little Endian,最高位放,叫做BigEndian,Tcp/ip协议就是按照BigEndian做的,而X86机器多按照Little Endian设计,所以发出去需要做一个转换

4.如何知道一个服务器实现了哪些远程调用,如何访问这些远程调用

假设有服务器端实现了多个远程调用,每个可能在不同的进程中,对应的端口也不一样,而服务器端是自己的实现的,不能大家都用一个公认的端口,那么如何查找呢?

5.发生了错误,重传,丢包,性能上的问题,怎么办

本地调用没有问题,但是一旦在网络上,问题都需要有保证,因为网络的不可靠性,所以虽然在一个连接中,有着TCP的保护,但是服务器崩了,怎么办?TCP就无法起作用了

那么,基于上面的问题,我们怎么办?

图片

本地调用函数中,很多事情,都有着编译器去处理

但是在远程调用中,很多事情都需要重新去操作

在很多公司的解决方案中,可以是弄一个核心的通信组,里面都是精通Socket编程的人,实现一个统一的库,让其他的业务组来调用,业务中的人不需要知道中间传输的细节,通信双方的语法,语义,格式,端口,错误处理,都需要调用方和被调用方开会协商,双方达成一致,一旦有一方改变,要及时商议解决,不然可能出现通信问题

不过,这种大牛团队,只有大公司才能配得起,有没有实现好的框架可以使用呢?

于是,有一个大牛写了一个论文,定义了RPC的调用标准,后面所有的PRC框架,都是按照这个标准来的

图片

当客户端的应用想要发起一个远程调用的时候,是通过本地调用调用了本地的Stub,将调用的接口,方法,参数,通过约定的协议规范进行编码,并且通过本地的RPCRuntime进行传输,调用网络包传到服务器上

服务器端的RPCRuntime收到了请求,交给了提供方Stub进行解码,然后调用服务端的方法,服务端执行方法,返回结果,提供方Stub将返回的结果编码后,发送给客户端,客户端的RPCRuntime收到了结果,发给调用方

这里面传数中,对于用户层和服务端,都是好像本地调用一样,专注于业务逻辑的处理就可以了,对于Stub层,处理双方约定好的语法,语义,封装,解封装,对于RPCRuntime,主要处理些高性能的传输

早期的Sun RPC或者就是使用了NFS协议实现的

NFS就是网络文件系统,要使用这个系统,要启用两个服务端,一个是mountd,用来挂载文件路径,一个是nfsd,用来读写文件,NFS可以再本地mount一个远程的目录到本地的目录,而本地的用户在这个目录里面写入,读取的时候,实际操作的是远程的另一个机器的文件

操作远程和远程调用的思路是一样,就好比操作本地有一样,所以NFS协议就是基于RPC实现的,无论是什么RPC,底层都是Socket编程

图片

XDR是一个标准的数据压缩格式,可以表示基本的数据类型,也可以表示结构体

简单来说的几种基本数据类型

图片

在RPC的调用过程中,所有的数据类型都要封装为类似的格式,RPC的调用和结果返回,也有着严格的格式

XID:唯一标识一对请求和恢复,请求是0,回复是1

RPC有版本号:两端是匹配PRC协议的版本号,如果不匹配,就会返回Deny,原因是RPC_MISMATCH

程序也有着编号,如果服务端找不到这个程序,就会返回PROG_UNAVAIL

程序还有着版本号,如果版本号不匹配,会返回PROG_MISMATCH

一个程序中存在着多个方法,方法也有编号,如果找不到方法,就会返回PROC_UNAVAIL

调用需要认证鉴权,如果不通过,也是Deny

最后是参数列表,如果参数无法解析,则返回GABAGE_ARGS

图片

为了可以成功的调用RPC,可以再客户端和服务端实现RPC的时候,定义一个双方都认可的程序,版本,方法,参数等

图片

上面的加法,双方约定为一个协议定义文件,

利用这个文件,RPC提供了一个工具,而且根据这个文件,生成客户端和服务器端的Stub程序

图片

最下层的是XDR文件,用于编码和解码参数,这个文件是客户端和服务端共享的,所以需要双方一致

在客户端,会调用clnt_create创建一个连接,然后调用add_1,这是一个Stub函数,跟调用本地一样,其实这个函数发起了一个RPC的调用,通过即时的clnt_call来调用ONE_RPC的类库,真正用来发消息的,非常复杂

服务端也会有一个Stub程序,用于监听客户端的请求,当调用到达的时候,判断是哪个函数,然后进行逻辑执行

有了这个RPC的框架,就可以解决前面的几个问题了,对于,如何规定远程的调用语法,如何传递参数,如何表示数据,这几个问题被称为协议约定问题

传输问题

对于错误,重传,丢包的问题,我们还没有解决,这一类问题称为传输问题,这个交给了ONE RPC的类库去实现

图片

对于每一个客户端,都会创建一个传输管理层,对于每一个RPC调用,都是一个任务,在传输层,可以看到熟悉的队列机制,拥塞窗口机制

在网络传输的过程,需要等待消息的返回,同步的等待效率比较低下,因此有Scoket的异步模型,为了能够异步处理,对于远程调用单位,可以通过状态机来进行实现,只有满足了某个状态,才能进行下一步,不满足,就只能等待,在等待的时候,其他的RPC调用可以继续执行

图片

从进入初始状态,查看RPC的传输层队列有无空闲的位置,处理新的RPC任务,

连接有了空闲,可以连接后,需要等待连接后的结果,会有连接失败的时候,如果连接成功了,则发送RPC请求,等待RPC的结果,在这个过程中,需要一定的事件,如果出现了错误,可以进行重新连接

这里处理了连接失败,重试,发送失败,超时,重试的场景,不是大牛写不出来,所以实现了一个RPC的框架,很有难度

服务发现问题

在解决了传输问题之后,还有着一个如何找到RPC服务端的那个随机端口,这就是服务发现问题

在ONE RPC中,服务发现是通过portmapper实现的

图片

portmapper启动在一个众所周知的端口,RPC程序会启动在一个随机端口上,然后向portmapper注册,客户端要访问RPC服务端这个程序的时候,首先查询portmapper,获取RPC服务端的随机端口,然后向这个随机端口建立连接,开始RPC调用

本章小结:

远程调用使用Socket编程就可以了,但是Socket编程即为复杂,需要解决网络协议约定问题,传输问题,服务发现问题

早期的RPC框架和NFS的实现,给出了这三个问题的示范性的实现,协议约定用公用的协议描述文件,并且通过这个文件生成Stub程序,RPC的传输需要一个状态机,还需要一个进程专门做服务发现

课后思考:

1.mount是通过的系统调用,最终调用到了RPC层,一旦mount完成了,就像是写入本地文件一样写入NFS了,如何触发RPC的呢?

2.ONE RPC是早起的RPC框架,存在什么问题呢?

1.RPC调用存在于读写操作的时候,调用的操作系统的读写接口,nfs对接口进行了实现,实现的代码中封装了RPC

而且,nfs挂载的时候指定了文件系统类型,应用对文件进行read write等操作的时候,会调用系统底层的vfs文件系统相关的函数,nfs实现了vfs规定的接口函数,调用vfs相关函数时候vfs会调用nfs的实现,实现访问远程文件系统

在Linux之中,很多东西都是文件,因此内核之中,有一个打开的文件列表File list,每个打开的文件都有这一项

图片

对于Socket来说,in-core inode 就是内存之中的inode,对于nfs来说,也有一个inode,这个inode里面有一个成员变量 file_operations,这里面是这个文件系统的操作函数,对于nfs来说,因为有nfs_file_read,nfs_file_wirte,所以在一个mount的路径之中,读取某个文件,就会调用这个函数

2.因为双方都拥有接口描述文件,有文件就需要双方做信息交换,所以双方并不完全透明

XDR有着严格的格式限制,两端必须完全匹配,所以对于灵活的数据格式,无法很好的支持

现在的RPC框架,更像是一个生态,不仅仅是RPC框架,更像是一个生态,内部包含了分布式配置 Nacos,服务注册和发现,服务调用,熔断,负载均衡

发表评论

邮箱地址不会被公开。 必填项已用*标注