submitJob
提交作业:
这里的jobID
就是先前 Client 向 RS 申请并返回的jobID
:
这里的
ClientProtocol
其实就是YARNRunner
:
提交任务程序:
然后是很多很多层的封装和调用
跳过--------
进入 org.apache.hadoop.ipc.ProtobufRpcEngine
$Invoker
:
Invoker{
...
public Object invoke(Object proxy, Method method, Object[] args)
throws ServiceException {
// 制作请求的头协议
// 查看rpcRequestHeader的值:
RequestHeaderProto rpcRequestHeader = constructRpcRequestHeader(method);
// Wrapper包装类
final RpcResponseWrapper val;
try {
// 在构造RpcRequestWrapper类的同时调用了org.apache.hadoop.ipc.Client.call()方法
// 涉及到了hadoop的底层
// 该方法的作用:传入前面封装的RpcRequestWrapper类的对象,带上RPC的类型,套接字的远程地址(8032端口,即资源管理器)
val = (RpcResponseWrapper) client.call(RPC.RpcKind.RPC_PROTOCOL_BUFFER,
// 把头和消息加在一起构成了Wrapper包装类
new RpcRequestWrapper(rpcRequestHeader, theRequest), remoteId,
fallbackToSimpleAuth);
} catch{
...
}
...
}
...
}
call
存放的是提交到当前这个连接的请求对象。
Call
对象就表示一次远程过程调用业务,因此它含有远程调用业务所需要的参数信息。
进入 org.apache.hadoop.ipc.Client
$call
:
它做了如下工作:
- 创建一个Call对象,将
rpc
的操作类型和request
传入 connection.sendRpcRequest(call)
,传入call
对象,通过连接去发送**RPC
** 请求call.wait()
,等待返回结果
由于 call.wait()
会等待返回结果,所以必然有一个过程去设置 call
的调用状态:
通过向远程服务器发送 rpc
请求来启动 rpc
调用:
sendRpcRequest(..){
...
// 先将call对象写入到当前的数据输出缓冲区
final DataOutputBuffer d = new DataOutputBuffer();
// 制作了RPC请求的头协议
RpcRequestHeaderProto header = ProtoUtil.makeRpcRequestHeader(
call.rpcKind, OperationProto.RPC_FINAL_PACKET, call.id, call.retry,
clientId);
// 将协议头写入到缓冲区
header.writeDelimitedTo(d);
// 将call对象的RPC请求也写入了缓冲区
call.rpcRequest.write(d);
// 将数据都写入了DataOutputBuffer里去了,DataOutputBuffer继承了DataOutputStream
...
...
// 使用了同步机制
synchronized (sendRpcRequestLock) {
// senderFuture即为在线程池中,将来某个阶段要运行的程序
Future<?> senderFuture = sendParamsExecutor.submit(new Runnable() {
@Override
public void run() {
try {
// Connection.this.out为连接中的流对象(连接中的数据流)
synchronized (Connection.this.out) {
if (shouldCloseConnection.get()) {
return;
}
if (LOG.isDebugEnabled())
LOG.debug(getName() + " sending #" + call.id);
// d为本地存放的缓冲区数据 得到d中的所有数据
byte[] data = d.getData();
// 得到数据长度
int totalLength = d.getLength();
// 把长度写入输出流
out.writeInt(totalLength); // Total Length
// 把数据写入到输出流中去
out.write(data, 0, totalLength);// RpcRequestHeader + RpcRequest
// 清理输出流
out.flush();
// 至此,客户端往服务端的消息发送完毕
// out:DataOutputStream --> BufferedOutputStream --> SocketOutputStream --> SocketOutputStream$Writer --> SocketChannel
}
}
...
}