RPC调用;
RPC(remote procedure call)远程过程调用;
不同java进程间的对象方法的调用。
一方称作服务端(server),一方称为客户端(client);
server端提供对象,共客户端调用的, 被调用的对象的执行发生在server端。
RPC是hadoop框架运行的基础(hadoop是建立在RPC机制之上的,建立c/s模式上的);
使用hadoop的RPC做一个小例子,理解hadoop体系结构运行的原理:
先运行 MyServer 在运行MyClient
package rpc; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; import org.apache.hadoop.ipc.RPC.Server; public class MyServer { public static final String SERVER_ADDRESS = "localhost"; public static final int SERVER_PROT = 12345; //Server端提供对象的方法供客户端运行的, public static void main(String[] args) throws Exception { /** * 构造 an RPC server. * @param instance 实例中的方法会被客户端调用,特点:要实现VersionedProtocol接口,还必须是一个接口 * 在客户端 要调用的方法必须在我们这个对象的接口中 * @param bindAddress 绑定的这个地址用语监听连接的到来 * @param port 绑定的这个端口用语监听连接的到来 * @param conf the configuration to use */ Server server = RPC.getServer(new MyBiz(), SERVER_ADDRESS, SERVER_PROT, new Configuration()); server.start(); } }
package rpc; import java.net.InetSocketAddress; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; public class MyClient { public static void main(String[] args) throws Exception { /**构造一个客户端的代理对象,这个代理对象实现了一个指定的协议, *这个协议可以和指定地址的服务端通信的 * Construct a client-side proxy object that implements the named protocol, * talking to a server at the named address. */ MyBizable proxy = (MyBizable) RPC.waitForProxy(MyBizable.class, MyBizable.VERSION, new InetSocketAddress(MyServer.SERVER_ADDRESS, MyServer.SERVER_PROT), new Configuration()); String result = proxy.hello(" world!"); System.out.println("客户端调用的结果:" + result); RPC.stopProxy(proxy); } }
package rpc; import org.apache.hadoop.ipc.VersionedProtocol; public interface MyBizable extends VersionedProtocol{ public static final long VERSION=12312322L; public abstract String hello(String name); }
package rpc; import java.io.IOException; public class MyBiz implements MyBizable{ /* (non-Javadoc) * @see rpc.MyBizable#hello(java.lang.String) */ @Override public String hello(String name){ //却换的Server短输出台查看是否打印这句,说明是在server执行的 System.out.println("我被调用了"); return "hello"+name; } @Override public long getProtocolVersion(String protocol, long clientVersion) throws IOException { return MyBizable.VERSION; } }
通过例子获得的认识:
服务端提供的对象必须是一个接口,接口extends VersionedProtocol接口,为什么?因为JDK反射代理要求必须是一个接口。
客户端能够调用的对象中的方法必须位于对象的接口中;
这个就是RPC通信;
使用cmd jps可以查看到MyServer,说明hadoop start-all.sh里面的五个java进程指的是RPC的服务端(可以通过查看源码NameNode的mian方法点去看);
我们观察 NameNode 的源代码,可以看到 NameNode 确实创建了RPC 的服务端。
具体步骤:
NameNode的main方法→createNameNode→
new NameNode→initialize→ 如下图
// create rpc server InetSocketAddress dnSocketAddr = getServiceRpcServerAddress(conf); if (dnSocketAddr != null) { int serviceHandlerCount = conf.getInt(DFSConfigKeys.DFS_NAMENODE_SERVICE_HANDLER_COUNT_KEY, DFSConfigKeys.DFS_NAMENODE_SERVICE_HANDLER_COUNT_DEFAULT); this.serviceRpcServer = RPC.getServer(this, dnSocketAddr.getHostName(), dnSocketAddr.getPort(), serviceHandlerCount, false, conf, namesystem.getDelegationTokenSecretManager()); this.serviceRPCAddress = this.serviceRpcServer.getListenerAddress(); setRpcServiceServerAddress(conf); } this.server = RPC.getServer(this, socAddr.getHostName(), socAddr.getPort(), handlerCount, false, conf, namesystem .getDelegationTokenSecretManager()); // The rpc-server port can be ephemeral... ensure we have the correct info this.serverAddress = this.server.getListenerAddress(); FileSystem.setDefaultUri(conf, getUri(serverAddress)); LOG.info("Namenode up at: " + this.serverAddress);