Hadoop源码分析(13)
1、 HDFS远程调用(RPC)分析
在文档(12)中分析了在HA状态下,读取editlog的操作。 最后分析到了它会通过IPCLoggerChannel对象新建一个线程,让这个线程去执行 RPC操作,通过RPC获取journalnode的数据。
RPC简介
RPC即远程调用。RPC的应用场景很简单。假设有AB两台机器, 两台机器上运行着两个不同的程序。这时A需要调用一个方法C, 但是方法C是运行在B上的。因此,A需要将要执行的方法名和执行需要的参数传给B, 然后B找到这个方法并执行,执行完成后将结果返回给A。这便是远程调用。 如下图所示:
若将上述场景带入到之前分析的源码中的话,A上运行的便是namenode, B上运行的便是journalnode(实际情况中journalnode和namenode都运行在 不止一台机器上)。其中namenode是负责管理hdfs元数据的,journalnode是 负责存储namenode的操作日志的。如同之前分析的一样,在namenode启动的时候 需要加载操作日志用于恢复元数据,这时namenode需要知道journalnode中存储 了哪些操作日志。journalnode中存储了哪些日志一定是journalnode最清楚, 所以这个方法一定是有journalnode实现的。所以对于namenode来说,只需要调 用journalnode的方法便可。
RPC使用
HDFS在实际使用的时候,不像上述介绍的那么简单,它对client和 server段都进行了一定程度的封装。使得RPC独立成为一个模块,可以使用自定 义的代码来调用HDFS的RPC。在使用RPC的时候步骤如下:
首先需要定义一个接口,这个接口需要继承hadoop的 VersionedProtocol接口。接口的方法是需要远程调用的方法。 示例如下:
public interface IProxyProtocol extends VersionedProtocol{
long versionID=0001;
String dosomething(int num,String str);
}
然后是实现server端,因为server端是正在执行方法的地方 所以server端需要有实现上述定义的接口的类,并将这个类实例化并绑定到 server中。使用示例如下:
public class IServer implements IProxyProtocol {
public static final int PORT=8888;
public static final String ADDRESS="127.0.0.1";
@Override
public long getProtocolVersion(String protocol, long clientVersion) throws IOException {
System.out.println("server version:"+IProxyProtocol.versionID);
return IProxyProtocol.versionID;
}
@Override
public String dosomething(int num, String str) {
System.out.println("server : num="+num+" String="+str);
return str+" server";
}
@Override
public ProtocolSignature getProtocolSignature(String protocol, long clientVersion, int clientMethodsHash)
throws IOException {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) throws HadoopIllegalArgumentException, IOException {
Server server=new RPC.Builder(new Configuration())
.setProtocol(IProxyProtocol.class)
.setInstance(new IServer())
.setBindAddress(ADDRESS)
.setPort(PORT)
.build();
server.start();
}
}
这段代码很简单,首先是IServer类实现上述定义的IProxyProtocol 接口。然后在其main方法中使用RPC的Builder创建一个server并将接口与 Iserver对象绑定到server中,最后再启动server。
然后是客户端,客户端只需要创建代理对象,然后利用代理对象的方法 将需要执行的方法与参数发送给服务端便可。使用示例如下:
public class IClient {
public static void main(String[] args) throws IOException {
IProxyProtocol proxy=RPC.getProxy(IProxyProtocol.class,
IProxyProtocol.versionID,
new InetSocketAddress("127.0.0.1", 8888) ,
new Configuration());
String result=proxy.dosomething(1, "test");
System.out.println(result);
RPC.stopProxy(proxy);
}
}