本文主要是介绍Hadoop?RPC子系统的关键模块的结构和流程。
HadoopRPC逻辑上分成三部分,如上图所示。
RPC对外接口。
RPC服务端的实现。
RPC客户端的实现。
RPC是对外的接口类,主要提供两个方法:getProxy和getServer。
??说明
RPC服务端接口。为指定协议的实例,在指定的地址和端口上启动服务。
??函数原型
public?static?Server?getServer(
????????????????????final?Object?instance,
????????????????????final?String?bindAddress,
????????????????????final?int?port,
????????????????????final?int?numHandlers,
????????????????????final?boolean?verbose,
????????????????????Configuration?conf)?throws?IOException;
??参数说明
1)?Instance
RPC?Server端对象实例,也就是RPC?Client调用的接口实例。
2)?bindAddress
RPC?Server监听的IP地址。
3)?Port
RPC?Server监听的端口号。
4)?numHandlers
处理Call队列的Handler线程个数。
5)?Verbose
6)?conf
配置项。
??说明
RPC客户端接口,创建一个指定服务端的代理。
??函数原型
public?static?VersionedProtocol?getProxy(
????????????????????Class<??extends?VersionedProtocol>?protocol,
????????????????????long?clientVersion,
????????????????????InetSocketAddress?addr,
????????????????????UserGroupInformation?ticket,
????????????????????Configuration?conf,
????????????????????SocketFactory?factory)?throws?IOException;
??参数说明
1)?protocol
RPC?Server提供RPC服务的接口。
2)?clientVersion
客户端的版本号。
3)?addr
RPC?Server地址。
4)?ticket
5)?conf
配置项。
6)?factory
SOCKET工厂。
抽象的RPC服务,提供Call队列。
Server的实现。
RPC服务端的监听者,用来接受RPC客户端的连接请求和数据的收发。
RPC服务端的Call处理者,和Server.Listener通过Call队列交互。
RPC服务端的响应者。Server.Handler向RPC客户端发送响应是异步非阻塞的,如果有未发送出的数据,交由Server.Responder来完成。
提供接收数据,解析数据包的功能。
持有客户端的Call信息。
接收RPC?Client的调用,并编码成Call对象,放入到Call队列中,这个过程在Listener线程中完成。
??步骤说明:
1)?Listener线程循环等待RPC客户端的发送数据过来
2)?当有数据可以接收时,调用Connection的readAndProcess方法
3)?Connection边接收边对数据进行处理,如果接收到一个完整的Call包,则构建一个Call对象,并将这个Call对象PUSH到Call队列中,由Handler线程来处理Call队列中的所有Call。
处理Call队列中的每个请求,在Handler线程中完成。
??步骤说明:
1)?Handler线程循环监听Call队列,如果Call队列为空,则进入wait状态,否则按FIFO规则从Call队列取出Call
2)?将Call交给RPC.Server处理(调用RPC.Server的Call)
3)?借助JDK提供的Method,完成对目标方法的调用
4)?返回响应。由于响应需要通过SOCKET返回给RPC客户端,所以响应的类型必须是Writable。
RPC客户端的实现和入口类。
到RPC服务端对象连接的标识。
存储Call调用信息。
存储响应。
对InvocationHandler的实现,提供invoke方法,截获RPC客户端对RPC服务端对象的调用。
用来序列化和反序列化RPC客户端的调用信息,包括方法名和参数信息。
客户端RPC调用的处理流程,转化为SOCKET通信。
??步骤说明:
1)?RPC客户端发起一个RPC调用时,JAVA的反射机制会截获该调用,并转化为对Client.call的调用
2)?调用getConnection建立到RPC服务端的连接
3)?通过Connection将序列化后的参数发送到RPC服务端
4)?等待RPC服务端返回响应。
该流程用来建立到RPC?Server端的连接,到一个RPC?Server端只会建立一个连接。
??步骤说明:
1)?根据RPC服务端的地址和接口从连接池中获取一个,如果取到Connection则直接返回
2)?否则新建一个Connection,并将它放入到连接池中
3)?然后通过SocketFactory创建一个Socket,并建立到RPC服务端的连接,如果连接不成功,则重试
4)?创建和关联输入和输出流对象。
客户端发起的RPC调用都是同步的,而服务端处理RPC调用是异步的。客户端调用线程以阻塞同步的方式发起RPC连接,及RPC调用,将参数等信息发送给Listener,然后就等待Connection接收完响应返回。
Listener负责接收RPC连接,和RPC数据,当一个Call的数据接收完后,组装成Call,并将Call放入由Handler提供的Call队列中。
Handler线程一直监听Call队列,如果Call队列不为空,则按队列方式取出一个Call,并转为实际调用,以非阻塞方式将响应发回给Connection,剩下未发送完毕的响应交给Responder处理。