RPC
远程过程调用RPC,就是客户端基于某种传输协议通过网络向服务提供端请求服务处理,然后获取返回数据(对于ONE WAY模式则不返还响应结果);而这种调用对于客户端而言,和调用本地服务一样方便,开发人员不需要了解具体底层网络传输协议。简单讲,就是本地调用的逻辑处理的过程放在的远程的机器上,而不是本地服务代理来处理。
RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。
LPC & IPC
既然存在RPC这种远程过程调用,必然会有与之对应的本地过程调用了。本地过程调用在不同的操作系统中,叫法不同,使用方式也不太一样。在Windows编程中,称为LPC;在linux编程中,更习惯称之为IPC,即进程间通信。
但是,不管如何,其本质上就是本地机器上的不同进程之间通信协作的调用方式。
Linux环境下 IPC实现方式:
- 管道
管道命令,其实内部实现就是使用的linux管道接口,每个命令其实是一个进程,各个进程的标准输出STDOUT,作为下一个进程的标准输入STDIN。
- 共享内存
进程和线程最大的区别就是一些资源是否隔离。也就是说,不同的进程,其内存资源使用是隔离独立的,每个进程有自己的一套内存地址映射逻辑,也即是系统是无法直接从不同进程的相同虚拟内存地址找到共同的物理内存地址的,这样,就无法像线程一样,简单把数据对象设置为static然后线程间就可以共享获取了。
因此,Linux对外提供了共享内存的方法来完成进程间通信。
- 信号量
Linux中的信号量和Java中的信号量一样,其主要用处是同步协作。
信号量其实就是一个比较特殊的变量,然后对它的操作都是原子进行的,并且一般只提供两种方法:P和V操作(在java中为wait()和notify())。
信号量的主要作用就是同步,所以我们一般是使用共享内存方式完成进程间通信,而在此过程中通过信号量来完成多进程间的同步协调机制。
- Socket套接字
上面的几个API方法可以看到都是利用单机同用一套资源,然后各自进程的资源之间通过内核方式或者内存方式协作完成单机多进程间通信。
此外,还有一种方式来完成进程间通信,就是套接字socket。Socket一般情况下是用在不同的两台机器的不同进程之间通信的,当Socket创建时的类型为 AF_LOCAL或AF_UNIX时,则是本地进程通信了(当然你也可以直接使用网络套接字,如果你觉得走下网络更酷,或者以后便于服务分离)。
通用RPC架构
远程过程调用RPC就是本地动态代理隐藏通信细节,通过组件序列化请求,走网络到服务端,执行真正的服务代码,然后将结果返回给客户端,反序列化数据给调用方法的过程。
通用的RPC组件一般包括以下一些模块:
serviceClient:这个模块主要是封装服务端对外提供的API,让客户端像使用本地API接口一样调用远程服务。一般,我们使用动态代理机制,当客户端调用api的方法时,serviceClient会走代理逻辑,去远程服务器请求真正的执行方法,然后将响应结果作为本地的api方法执行结果返回给客户端应用。类似RMI的stub模块。
processor:在服务端存在很多方法,当客户端请求过来,服务端需要定位到具体对象的具体方法,然后执行该方法,这个功能就由processor模块来完成。一般这个操作需要使用反射机制来获取用来执行真实处理逻辑的方法,当然,有的RPC直接在server初始化的时候,将一定规则写进Map映射中,这样直接获取对象即可。类似RMI的skeleton模块。
protocol:协议层,这是每个RPC组件的核心技术所在。一般,协议层包括编码/解码,或者说序列化和反序列化工作;当然,有的时候编解码不仅仅是对象序列化的工作,还有一些通信相关的字节流的额外解析部分。序列化工具有:hessian,protobuf,avro,thrift,json系,xml系等等。在RMI中这块是直接使用JDK自身的序列化组件。
transport:传输层,主要是服务端和客户端网络通信相关的功能。这里和下面的IO层区分开,主要是因为传输层处理server/client的网络通信交互,而不涉及具体底层处理连接请求和响应相关的逻辑。
I/O:这个模块主要是为了提高性能可能采用不同的IO模型和线程模型,当然,一般我们可能和上面的transport层联系的比较紧密,统一称为remote模块。
2
3
4
5
6
7
8
9