Hadoop RPC 源码阅读3

DataNode要向NameNode发送请求,希望得到一个应答,Datanode是通过调用RPC类的getProxy方法在本地创建一个Namenode的代理,getProxy使用动态代理机制来创建一个指定服务端的代理。

下面分析ipc.RPC源码



ipc.RPC源码分析:


RPC中有一些内部类,除了前面提到的RPC.Server中之外,还有Invocation、ClientCache、Invoker等。

下面先看RPC的getProxy()方法:

  /** Construct a client-side proxy object that implements the named protocol,
   * talking to a server at the named address. */
  public static VersionedProtocol getProxy(
      Class<? extends VersionedProtocol> protocol,
      long clientVersion, InetSocketAddress addr, UserGroupInformation ticket,
      Configuration conf, SocketFactory factory, int rpcTimeout) throws IOException {

    if (UserGroupInformation.isSecurityEnabled()) {
      SaslRpcServer.init(conf);
    }
    VersionedProtocol proxy =                                 // 通过Invoker类来 获取一个代理实例
        (VersionedProtocol) Proxy.newProxyInstance(
            protocol.getClassLoader(), new Class[] { protocol },
            new Invoker(protocol, addr, ticket, conf, factory, rpcTimeout));  
    long serverVersion = proxy.getProtocolVersion(protocol.getName(), 
                                                  clientVersion);
    if (serverVersion == clientVersion) {
      return proxy;
    } else {
      throw new VersionMismatch(protocol.getName(), clientVersion, 
                                serverVersion);
    }
  }

RPC的内部类Invoker类的继承自InvocationHandler,下面看一下Invoker.invoker()方法:

    public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
      final boolean logDebug = LOG.isDebugEnabled();
      long startTime = 0;
      if (logDebug) {
        startTime = System.currentTimeMillis();
      }

      ObjectWritable value = (ObjectWritable)
        client.call(new Invocation(method, args), remoteId); // 将方法名和参数封装为一个Invocation对象传给client对象的call方法,获得服务器的返回结果值
      if (logDebug) {                                     // 这里,client的call会对这些请求参数做处理,发给服务器端,具体分析见前文ipc.Client的源码分析。
        long callTime = System.currentTimeMillis() - startTime;
        LOG.debug("Call: " + method.getName() + " " + callTime);
      }
      return value.get();
    }







以下是Hadoop RPC机制的一个剪影。




客户端调用NameNode的方法,就要获取NameNode的实例对象。
这样客户端首先调用RPC类中的getProxy方法,getProxy返回NameNode实例。
在getProxy中,首先RPC会生成一个Data对象data,给data设置方法名,函数名,
将当前的data传给Client,Client会与Server通信,获取一个完整的data。
与此同时,server端会调用RPC的getServer方法,要求启动Server实例,
Server实例启动后,收到Client发来的data,然后Server获取一个NameNode实例,
并将NameNode实例和data实例传递给Handler类,Handler通过反射机制设置Data,
Server与Client通信,将包含NameNode完整信息的实例data传给Client,由此getProxy方法获得NameNode实例
客户端获取NameNode实例,调用NameNode方法。

package Test;

import NameNode.NameNode;
import RPC.RPC;


public class TestRpcClient {
	
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			  new Thread(new Runnable() {
	                @Override
	                public void run() {
	                    try {
	                        NameNode nameNode = RPC.getProxy(NameNode.class, "127.0.0.1", 8888);
	                        System.out.println(nameNode.doSomething1("我想做个代理!"));
	                    } catch (Exception e) {

	                    }
	                }
	            }).start();
		}
	}
}
package RPC;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;


import server.Server;

import Client.Client;
import Data.Data;
import NameNode.NameNode;

public class RPC {
	
	//start a server
	public static void getServer(NameNode nn, String host, int backlog, int port) throws UnknownHostException, IOException {
		ServerSocket ss = new  ServerSocket(port, backlog, InetAddress.getByName(host));
		while (true) {
			Socket s = ss.accept();
			new Server(nn, s).start();
		}
	}
	
	//start a client connecting to the given server
	public static NameNode getProxy(Class clazz, String host, int port) {
		 Class[] interfaces = new Class[1];
	     interfaces[0] = clazz;
	     return  (NameNode) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new InvocationHandler() {
	            @Override
	            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	                Data data = new Data();
	                data.setMethodName((String) method.getName());
	                data.setParaName((String) args[0]);
	                return Client.processClient(data, "127.0.0.1", 8888).getReturnValue();
	            }
	        });
	}
	
}

package Client;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import Data.Data;

public class Client {
	public static Data processClient(Data data, String host, int port) throws UnknownHostException, IOException, ClassNotFoundException {
	    Socket socket = new Socket(host,port);
       
	    //send a message to a given server
	    ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        objectOutputStream.writeObject(data);
        objectOutputStream.flush();
        
        //get message from server
        ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
        data = (Data) objectInputStream.readObject();
        
        //close connection
        objectOutputStream.close();
        objectInputStream.close();
        
        return data;
	}
}
package Data;

import java.io.Serializable;

public class Data implements Serializable{
	public String getMethodName() {
		return methodName;
	}
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	public String getParaName() {
		return paraName;
	}
	public void setParaName(String paraName) {
		this.paraName = paraName;
	}
	public String getReturnValue() {
		return returnValue;
	}
	public void setReturnValue(String returnValue) {
		this.returnValue = returnValue;
	}
	private String methodName;
	private String paraName;
	private String returnValue;
}

package Test;

import NameNode.NameNodeImp;
import RPC.RPC;


public class TestRpcServer {
	 public static void main(String[] args) throws Exception{
	        RPC.getServer(new NameNodeImp(),  "127.0.0.1", 200,8888);
	    }
}


package server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;

import Data.Data;
import NameNode.NameNode;
import NameNode.NameNodeImp;

public class Server extends Thread{
	
	private NameNode nn;
	private Socket socket; 
	
	public Server(NameNode nn, Socket ss) {
		this.nn = nn;
		this.socket = ss;
	}
		
	public void run() {
		ObjectInputStream objectInputStream = null;
		try {
			objectInputStream = new ObjectInputStream(socket.getInputStream());
			Data data = (Data) objectInputStream.readObject();
			
			try {
				data = Handler.doMethod(nn, data);
				
				ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
	            objectOutputStream.writeObject(data);
	            objectOutputStream.flush();
	            objectOutputStream.close();
	            objectInputStream.close();
				
				
			} catch (NoSuchMethodException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SecurityException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	// apply java reflex 
	private static class Handler {
		public static Data doMethod(NameNode nn, Data data) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
			String methodName = data.getMethodName(); 
			System.out.println(methodName);
			Class clazz = nn.getClass();
			
			Method m = clazz.getMethod(methodName, String.class);
			String result = (String) m.invoke(nn, data.getParaName());
			
			data.setReturnValue(result);
			return data;
		}
	}
}

package NameNode;

public interface NameNode {
	public String doSomething(String message) ;
	
	public String doSomething1(String message);
}

package NameNode;

public class NameNodeImp implements NameNode{

	@Override
	public String doSomething(String message) {
		// TODO Auto-generated method stub
		return message+"Hello";
	}

	@Override
	public String doSomething1(String message) {
		// TODO Auto-generated method stub
		return message+ "Hello2";
	}

}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值