Hadoop源码分析6: RPC基本线程

1.客户端执行RPC.getProxy

 

Queryquery=(Query) RPC.getProxy(Query.class, MyServer.IPC_VER, addr, newConfiguration());

 

即调用方法:

publicstatic VersionedProtocol getProxy(

     Class<<spanlang="ZH-CN">? extends VersionedProtocol>protocol,

     long clientVersion,InetSocketAddress addr, Configuration conf)

 

会用反射调用以下方法:

 VersionedProtocolproxy =

      (VersionedProtocol) Proxy.newProxyInstance(

          protocol.getClassLoader(),new Class[] { protocol },

          new Invoker(protocol, addr,ticket, conf, factory, rpcTimeout));

 

再直接调用以下的InvocationHandler:

 

private staticclass Invoker implements InvocationHandler {

   private Client.ConnectionId remoteId;

   private Client client;

   private boolean isClosed = false;

 

   public Invoker(Class<?extends VersionedProtocol> protocol,

      InetSocketAddress address, UserGroupInformation ticket,

      Configuration conf, SocketFactory factory,

       intrpcTimeout) throws IOException {

     this.remoteId= Client.ConnectionId.getConnectionId(address,protocol,

        ticket, rpcTimeout, conf);

     this.client =CLIENTS.getClient(conf, factory);

   }

}

 

privatesynchronized Client getClient(Configurationconf,

      SocketFactory factory) {

     // Construct & cacheclient.  The configuration is only used fortimeout,

     // and Clients haveconnection pools.  So we can either (a) losesome

     // connection pooling andleak sockets, or (b) use the same timeout for all

     // configurations. Since the IPC is usually intended globally,not

     // per-job, we choose(a).

     Client client =clients.get(factory);

     if (client == null){

       client =new Client(ObjectWritable.class, conf, factory);

      clients.put(factory, client);

     } else {

      client.incCount();

     }

     return client;

   }

 

检查客户端版本,调用

 longserverVersion =proxy.getProtocolVersion(protocol.getName(), 

                                         clientVersion);

 

这时候开始真正的Socket连接

 

 publicObject invoke(Object proxy, Method method, Object[]args)

     throws Throwable {

     final boolean logDebug =LOG.isDebugEnabled();

     long startTime =0;

     if (logDebug) {

       startTime= System.currentTimeMillis();

     }

 

     ObjectWritablevalue = (ObjectWritable)

      client.call(new Invocation(method, args), remoteId);

     if (logDebug) {

       longcallTime = System.currentTimeMillis() - startTime;

      LOG.debug("Call: " + method.getName() + " " + callTime);

     }

     returnvalue.get();

   }

 

 publicWritable call(Writableparam, ConnectionId remoteId)  

                   throws InterruptedException,IOException {

   Call call = new Call(param);

   Connection connection = getConnection(remoteId,call);

   connection.sendParam(call);              // send theparameter

   boolean interrupted = false;

   synchronized (call) {

     while (!call.done){

       try{

        call.wait();                       // waitfor the result

       } catch(InterruptedException ie) {

        // save the fact that we wereinterrupted

        interrupted = true;

      }

     }

 

     if (interrupted) {

       // set theinterrupt flag now that we are done waiting

      Thread.currentThread().interrupt();

     }

 

     if (call.error != null){

       if(call.error instanceof RemoteException) {

        call.error.fillInStackTrace();

        throw call.error;

       } else {// local exception

        // use the connection because it will reflect anip change, unlike

        // the remoteId

        throwwrapException(connection.getRemoteAddress(),call.error);

      }

     } else {

       returncall.value;

     }

   }

 }

 

  private Connection getConnection(ConnectionIdremoteId,

                             Call call)

                             throws IOException,InterruptedException {

   if (!running.get()) {

     // the client isstopped

     throw new IOException("Theclient is stopped");

   }

   Connection connection;

  

   do {

     synchronized (connections){

       connection= connections.get(remoteId);

       if(connection == null) {

        connection = new Connection(remoteId);

        connections.put(remoteId,connection);

      }

     }

   } while (!connection.addCall(call));

   

   //we don't invoke the method below inside"synchronized (connections)"

   //block above. The reason for that is if theserver happens to be slow,

   //it will take longer to establish a connectionand that will slow the

   //entire system down.

   connection.setupIOstreams();

   return connection;

 }

 

新建一个org.apache.hadoop.ipc.Client.Connection线程

 

 

   private synchronized void setupIOstreams()throws InterruptedException {

     if (socket != null ||shouldCloseConnection.get()) {

      return;

     }

    

     try {

       if(LOG.isDebugEnabled()) {

        LOG.debug("Connecting to "+server);

      }

       shortnumRetries = 0;

       finalshort maxRetries = 15;

       Randomrand = null;

       while(true) {

        setupConnection();

        InputStream inStream =NetUtils.getInputStream(socket);

        OutputStream outStream =NetUtils.getOutputStream(socket);

        writeRpcHeader(outStream);

        if (useSasl) {

          final InputStream in2 =inStream;

          final OutputStream out2 =outStream;

          UserGroupInformation ticket =remoteId.getTicket();

          if (authMethod ==AuthMethod.KERBEROS) {

            if(ticket.getRealUser() != null) {

             ticket = ticket.getRealUser();

           }

          }

          boolean continueSasl =false;

          try{ 

           continueSasl = 

             ticket.doAs(new PrivilegedExceptionAction(){

               @Override

               public Boolean run() throwsIOException {

                 returnsetupSaslConnection(in2, out2);

               }

             }); 

          } catch (Exception ex){

            if (rand== null) {

             rand = new Random();

           }

           handleSaslConnectionFailure(numRetries++, maxRetries, ex,rand,

               ticket);

           continue;

          }

          if (continueSasl){

            // Saslconnect is successful. Let's set up Sasl i/o streams.

            inStream =saslRpcClient.getInputStream(inStream);

            outStream= saslRpcClient.getOutputStream(outStream);

          } else {

            // fallback to simple auth because server told us so.

            authMethod= AuthMethod.SIMPLE;

            header =new ConnectionHeader(header.getProtocol(),

               header.getUgi(),authMethod);

            useSasl =false;

          }

        }

        this.in = new DataInputStream(newBufferedInputStream

            (newPingInputStream(inStream)));

        this.out = new DataOutputStream

        (newBufferedOutputStream(outStream));

        writeHeader();

 

        // update last activity time

        touch();

 

        //start the receiver thread after the socket connection has been setup

       // 开启org.apache.hadoop.ipc.Client.Connection线程

        start();

        return;

      }

     } catch (IOException e){

      markClosed(e);

      close();

     }

   }

 

privatesynchronized void setupConnection()throws IOException {

     short ioFailures =0;

     short timeoutFailures =0;

     while (true) {

       try{

        this.socket =socketFactory.createSocket();

       this.socket.setTcpNoDelay(tcpNoDelay);

        

       

        if (UserGroupInformation.isSecurityEnabled()){

          KerberosInfo krbInfo= 

           remoteId.getProtocol().getAnnotation(KerberosInfo.class);

          if (krbInfo != null&& krbInfo.clientPrincipal() != null) {

            Stringhost = 

            SecurityUtil.getHostFromPrincipal(remoteId.getTicket().getUserName());

           

            // If hostname is a valid local address then bind socket to it

           InetAddress localAddr =NetUtils.getLocalInetAddress(host);

            if(localAddr != null) {

             this.socket.bind(newInetSocketAddress(localAddr, 0));

           }

          }

        }

        

        // connection time out is 20s

        NetUtils.connect(this.socket,server, 20000);

        if (rpcTimeout > 0) {

          pingInterval = rpcTimeout; // rpcTimeout overwrites pingInterval

        }

 

       this.socket.setSoTimeout(pingInterval);

        return;

       } catch(SocketTimeoutException toe) {

       

        if (updateAddress()) {

          timeoutFailures = ioFailures= 0;

        }

       

        handleConnectionFailure(timeoutFailures++, 45,toe);

       } catch(IOException ie) {

        if (updateAddress()) {

          timeoutFailures = ioFailures= 0;

        }

        handleConnectionFailure(ioFailures++,maxRetries, ie);

      }

     }

   }

 

 publicstatic void connect(Socketsocket, 

                        SocketAddressendpoint, 

                        int timeout) throwsIOException {

   if (socket == null || endpoint == null ||timeout < 0) {

     throw newIllegalArgumentException("Illegal argument forconnect()");

   }

   

   SocketChannel ch =socket.getChannel();

   

   if (ch == null) {

     // let the defaultimplementation handle it.

     socket.connect(endpoint,timeout);

   } else {

    SocketIOWithTimeout.connect(ch, endpoint, timeout);

   }

 

   // There is a very rare case allowed by the TCPspecification, such that

   // if we are trying to connect to an endpoint onthe local machine,

   // and we end up choosing an ephemeral portequal to the destination port,

   // we will actually end up getting connected toourself (ie any data we

   // send just comes right back). This is onlypossible if the target

   // daemon is down, so we'll treat it likeconnection refused.

   if (socket.getLocalPort() == socket.getPort()&&

      socket.getLocalAddress().equals(socket.getInetAddress())){

     LOG.info("Detected a loopbackTCP socket, disconnecting it");

     socket.close();

     throw newConnectException(

       "Localhosttargeted connection resulted in a loopback. " +

       "No daemonis listening on the target port.");

   }

 }

 

org.apache.hadoop.ipc.Client.Connection线程

 

publicvoid run(){

     if(LOG.isDebugEnabled())

      LOG.debug(getName() + ": starting, having connections" 

          +connections.size());

     while (waitForWork()) {//waithere for work - read or close connection

      receiveResponse();

     }     

     close();     

     if(LOG.isDebugEnabled())

      LOG.debug(getName() + ": stopped, remaining connections"

          +connections.size());

   }

 

   private void receiveResponse(){

     if(shouldCloseConnection.get()) {

      return;

     }

     touch();

     

     try {

      int id= in.readInt();                 // try toread an id

 

       if(LOG.isDebugEnabled())

        LOG.debug(getName() + " got value #" +id);

 

       Call call= calls.get(id);

 

      int state= in.readInt();    // read call status

       if (state== Status.SUCCESS.state) {

        Writablevalue = ReflectionUtils.newInstance(valueClass,conf);

       value.readFields(in);              // readvalue

        call.setValue(value);

        calls.remove(id);

       } else if(state == Status.ERROR.state) {

        call.setException(newRemoteException(WritableUtils.readString(in),

                                       WritableUtils.readString(in)));

        calls.remove(id);

       } else if(state == Status.FATAL.state) {

        // Close the connection

        markClosed(newRemoteException(WritableUtils.readString(in), 

                                 WritableUtils.readString(in)));

      }

     } catch (IOException e){

      markClosed(e);

     }

   }

将结果放在call.value里面。

取得结果以后,线程org.apache.hadoop.ipc.Client.Connection运行完成,自动退出。

 

2.执行 query.getFileStatus("/tmp/testIPC");

实际上跟执行getProtocolVersion是一样的。

 

3.执行RPC.stopProxy(query); 

 

 privatevoid stopClient(Clientclient) {

     synchronized (this){

      client.decCount();

       if(client.isZeroReference()) {

       clients.remove(client.getSocketFactory());

      }

     }

     if (client.isZeroReference()){

      client.stop();

     }

   }

 }

 

 public void stop(){

   if (LOG.isDebugEnabled()) {

     LOG.debug("Stoppingclient");

   }

 

   if (!running.compareAndSet(true, false)){

     return;

   }

   

   // wake up all connections

   synchronized (connections) {

     for (Connection conn :connections.values()) {

      conn.interrupt();

     }

   }

   

   // wait until all connections areclosed

   while (!connections.isEmpty()) {

     try {

      Thread.sleep(100);

     } catch (InterruptedExceptione) {

     }

   }

 }

 

4.执行server.stop()

 

 public synchronized void stop() {

   LOG.info("Stopping server on " +port);

   running = false;

   if (handlers != null) {

     for (int i = 0; i <handlerCount; i++) {

       if(handlers[i] != null) {

        handlers[i].interrupt();

      }

     }

   }

   listener.interrupt();

   listener.doStop();

   responder.interrupt();

   notifyAll();

   if (this.rpcMetrics != null) {

    this.rpcMetrics.shutdown();

   }

 }

 

 synchronized void doStop(){

     if (selector != null){

      selector.wakeup();

      Thread.yield();

     }

     if (acceptChannel != null){

       try{

        acceptChannel.socket().close();

       } catch(IOException e) {

        LOG.info(getName() + ":Exception in closinglistener socket. " + e);

      }

     }

    readPool.shutdown();

   }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值