既然是RPC,就一定有Client端和Server端,
如果进行一次HDFS的读写,其中一个DataNode需要跟NameNode建立连接,也需要和其他的DataNode建立连接,那么每一个Client需要维护多个连接。同时为了减少不必要的连接,Client的做法是拿Connectionid来作为Connection的ID。
RPC Client的结构
Client.ConnectionId:到RPC Server对象连接的标识(IP地址+端口号或者主机名+端口号)
Client.Call:Call调用的信息。
Client.ParallelResults:Call响应
RPC.Invoker:对InvocationHandler的实现,提供inovke方法,实现RPC.Client对RPC.Server对象的调用。
RPC.Invocation:用来序列化和反序列化RPC.Client的调用信息(主要跟前面讲的动态代理和Java反射机制有关)
RPC Client主要流程
每一个Call都是由RPC.Client发起的
1.RPC Client 发起RPC Call.通过Java反射机制转化为对Client.call调用
2.调用getConnection得到与RPC Server的连接,每一个RPC Client 都维护一个HashMap结构的到RPC Server的连接池
3.通过Connection将序列化后的参数发送到RPC服务器端
4.阻塞方式等待RPC服务端返回响应
在IPC下面,Server类是个抽象类,唯一抽象的地方是:
public abstract Writable call(Class<?> protocol, Writable param, long receiveTime)throws IOException;
这表示Server类提供了一个框架,Server具体的功能需要具体类来实现RPC Server的结构:
Server.Listener:RPC Server的监听者,用来接收RPC Client的连接请求和数据,其中将数据封装成CALL后PUSH到Call队列中
Server.Handler:RPC Server响应者,Server.Handler按照异步非阻塞的方式向RPC Client发送相应,如果有没有未发出的数据,交由Server.Responder来处理
Server.Connection:RPC Server数据的接受者,提供接受数据,解析数据包的功能,
Server.Call:持有客户端的Call信息
RPC Server的主要流程
RPC Server作为服务的提供者主要有两部分组成:接收Call调用和处理Call调用
接收Call调用负责接收来自RPC Client的调用请求,编码成Call对象放入到Call队列中,这个过程由Server.Listener来完成,
1.Lintener线程监听RPC Client发过来的数据
2.当有数据可以接收时,调用Connection的readAndProcess方法
3.Connection对边接收过来的数据边处理,当接收到一个完整的Call包,则构建一个Call对象,PUSH到Call队列中,PUSH到Call队列中,有Handler来处理Call队列中的所有Call,处理完的Call调用负责处理Call队列中的每一个调用请求,有Handler线程来完成。
1.Handler线程监听Call队列,如果Call队列非空,案FIFO规则从Call队列中取出Call
2.将Call交给RPC.Server来处理
3.借助 JDK提供的Method.完成对目标方法的调用,目标方案由具体的业务逻辑实现
4.返回相应,Server.Handler按照异步非阻塞方式向RPC Client发送响应,如果有没有发送出的数据,则交由Server.Responder来完成
完整的交互过程如下