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";
}
}