- RPC remote procedure call,"远程过程调用",NFS正是其中一种,此外NIS、hadoop也是使用rpc框架实现的。
所谓的remote procedure call,就是在本地调用远程主机上的procedure。以本地执行"cat -n ~/abc.txt"命令为例,在本地执行cat命令时,会发起某些系统调用(如open()、read()、close()等),并将cat的选项和参数传递给这些函数,于是最终实现了文件的查看功能。在RPC层面上理解,上面发起的系统调用就是procedure,每个procedure对应一个或多个功能。而rpc的全名remote procedure call所表示的就是实现远程procedure调用,让远程主机去调用对应的procedure。
上面的cat命令只是本地执行的命令,如何实现远程cat,甚至其他远程命令?通常有两种可能实现的方式:
(1).使用ssh类的工具,将要执行的命令传递到远程主机上并执行。但ssh无法直接调用远程主机上cat所发起的那些系统调用(如open()、read()、close()等)。
(2).使用网络socket的方式,告诉远程服务进程要调用的函数。但这样的主机间进程通信方式一般都是daemon类服务,daemon类的客户端(即服务的消费方)每调用一个服务的功能,都需要编写一堆实现网络通信相关的代码。不仅容易出错,还比较复杂。
而rpc是最好的解决方式。rpc是一种框架,在此框架中已经集成了网络通信代码和封包、解包方式(编码、解码)。以下是rpc整个过程,以cat NFS文件系统中的a.sh文件为例。
nfs客户端执行cat a.sh,由于a.sh是NFS文件系统内的文件,所以cat会发起一些procedure调用(如open/read/close),这些procedure和对应的参数会发送给rpc client(可能是单个procedure,也可能是多个procedure组合在一起一次性发送给rpc client,在NFSv4上是后者),rpc client会将这些数据进行编码封装(封装和解封装功能由stub代码实现),然后将封装后的数据通过网络发送给rpc server,rpc server会对封装的数据进行解封,于是就得到了要调用的procedures和对应的参数,然后将它们交给NFS服务进程,最终进行procedure的调用。NFS服务发起procedure调用后,会得到数据(可能是数据本身,可能是状态消息等),于是交给rpc server,rpc server会将这些数据封装并通过网络发送给rpc client,rpc client解封于是得到最终的返回结果。
从上面的过程可以知道,rpc的作用是数据封装,rpc client封装待调用的procedure及其参数,rpc server封装返回的数据。
所以注意,rpc的远程procedure调用的概念不是在本地向远程主机发起procedure的调用,而是将要执行的procedure包装后通过rpc发送出去,让远程主机上的对应程序自己去执行procedure并返回数据。也就是说rpc的作用是封装和发送,而不是发起调用。
举个更简单的例子,使用google搜索时,实现搜索功能的procedure和要搜索的内容就是rpc client封装的对象,也是rpc server要解封的对象,搜索的结果则是rpc server封装的对象,也是rpc client要解封的对象。解封后的最终结果即为google搜索的结果。
在CentOS 6/7上,rpc server由rpcbind程序实现,该程序由rpcbind包提供。
[root@xuexi ~]# yum -y install rpcbind [root@xuexi ~]# rpm -ql rpcbind | grep bin/ /usr/sbin/rpcbind /usr/sbin/rpcinfo
其中rpcbind是rpc主程序,在rpc服务端该程序必须处于已运行状态,其默认监听在111端口。rpcinfo是rpc相关信息查询工具。
对于rpc而言,其所直接管理的是programs,programs由一个或多个procedure组成。这些program称为RPC program或RPC service。
如下图,其中NFS、NIS、hadoop等称为网络服务,它们由多个进程或程序(program)组成。例如NFS包括rpc.nfsd、rpc.mountd、rpc.statd和rpc.idmapd等programs,其中每个program都包含了一个或多个procedure,例如rpc.nfsd这个程序包含了如OPEN、CLOSE、READ、COMPOUND、GETATTR等procedure,rpc.mountd也主要有MNT和UMNT两个procedure。
对于RPC而言,它是不知道NFS/NIS/hadoop这一层的,它直接管理programs。每个program启动时都需要找111端口的rpc服务登记注册,然后RPC服务会为该program映射一个program number以及分配一个端口号。其中每个program都有一个唯一与之对应的program number,它们的映射关系定义在/etc/rpc文件中。以后rpc server将使用program number来判断要调用的是哪个program中的procedure并将解包后的数据传递给该program。
例如只启动rpcbind时。
[root@xuexi ~]# systemctl start rpcbind.service [root@xuexi ~]# rpcinfo -p localhost program vers proto port service 100000 4 tcp 111 portmapper 100000 3 tcp 111 portmapper 100000 2 tcp 111 portmapper 100000 4 udp 111 portmapper 100000 3 udp 111 portmapper 100000 2 udp 111 portmapper
其中第一列就是program number,第二列vers表示对应program的版本号,最后一列为RPC管理的RPC service名,其实就是各program对应的称呼。
当客户端获取到rpc所管理的service的端口后,就可以与该端口进行通信了。但注意,即使客户端已经获取了端口号,客户端仍会借助rpc做为中间人进行通信。也就是说,无论何时,客户端和rpc所管理的服务的通信都必须通过rpc来完成。之所以如此,是因为只有rpc才能封装和解封装数据。
既然客户端不能直接拿着端口号和rpc service通信,那还提供端口号干嘛?这个端口号是为rpc server提供的,rpc server解包数据后,会将数据通过此端口交给对应的rpc service。