Hadoop 2.7.1-Yarn 源码分析(三) Client 正式提交应用程序到 RS

在这里插入图片描述

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
          }
        } 
    ...
  }

参考:https://blog.csdn.net/hellozhxy/article/details/82497235

猜你喜欢

转载自blog.csdn.net/qq_39327985/article/details/89531704